I created a custom form from a buildForm function. In this form, I would like add an image field.
I can do that via this code :
$form['main']['image'] = array(
'#type' => 'text_format',
'#title' => t('image'),
'#default_value' => array(10),
);
I can upload and remove the image from my form. However, when I upload an image, I haven't this preview. I mean, when I create a content via the Drupal UI. I can add a preconfigured "image" field. When I upload an image via this "image" field, I have a preview of the image.
And here, when I create the field element programmatically, I haven't a preview of the image when I upload her. How use api Drupal for have the preview of the image when I upload her via my "image" field ?
So here is how I got my form to display the thumbnail image. What I basically did was take the code in ImageWidget::process, put it in a theme preprocessor and set the #theme property of the element to image_widget.
Your image element in your form class should look like this:
$form['profile_image'] = [
'#type' => 'managed_file',
'#title' => t('Profile Picture'),
'#upload_validators' => array(
'file_validate_extensions' => array('gif png jpg jpeg'),
'file_validate_size' => array(25600000),
),
**'#theme' => 'image_widget',**
**'#preview_image_style' => 'medium',**
'#upload_location' => 'public://profile-pictures',
'#required' => TRUE,
];
In your name_of_default_theme.theme file, you need the following:
function name_of_default_theme_preprocess_image_widget(&$variables) {
$element = $variables['element'];
$variables['attributes'] = array('class' => array('image-widget', 'js-form-managed-file', 'form-managed-file', 'clearfix'));
if (!empty($element['fids']['#value'])) {
$file = reset($element['#files']);
$element['file_' . $file->id()]['filename']['#suffix'] = ' <span class="file-size">(' . format_size($file->getSize()) . ')</span> ';
$file_variables = array(
'style_name' => $element['#preview_image_style'],
'uri' => $file->getFileUri(),
);
// Determine image dimensions.
if (isset($element['#value']['width']) && isset($element['#value']['height'])) {
$file_variables['width'] = $element['#value']['width'];
$file_variables['height'] = $element['#value']['height'];
} else {
$image = \Drupal::service('image.factory')->get($file->getFileUri());
if ($image->isValid()) {
$file_variables['width'] = $image->getWidth();
$file_variables['height'] = $image->getHeight();
}
else {
$file_variables['width'] = $file_variables['height'] = NULL;
}
}
$element['preview'] = array(
'#weight' => -10,
'#theme' => 'image_style',
'#width' => $file_variables['width'],
'#height' => $file_variables['height'],
'#style_name' => $file_variables['style_name'],
'#uri' => $file_variables['uri'],
);
// Store the dimensions in the form so the file doesn't have to be
// accessed again. This is important for remote files.
$element['width'] = array(
'#type' => 'hidden',
'#value' => $file_variables['width'],
);
$element['height'] = array(
'#type' => 'hidden',
'#value' => $file_variables['height'],
);
}
$variables['data'] = array();
foreach (Element::children($element) as $child) {
$variables['data'][$child] = $element[$child];
}
}
The solution works well, but the image module is missing a class with the @FormElement annotation. That is why the element isn't rendered properly.