Imagine a profile that has an edit button to open a modal. The modal contains a profile image upload (managed_file field) and a listing of languages that the user speaks. Each languages has an edit button that opens another form to change the language proficiency.
- User open the form, add a profile image and save using ajax. It works.
- User open the form, made a change on one of the languages and save, it works. Then try to add a profile image, the saving fail.
Why 2 do not work?
Because managed_file ajax use the url of the language form instead of using the url of the forms it belongs.
This happens because RenderElement assign previous used URL when 'url' is set to NULL.
Currently ManagedFile don't allow to configure a custom 'url' in '#ajax'.
My proposed solution is to allow the use of '#ajax' parameter in managed_file to avoid this issue by setting custom 'url'
Proposed patch attached.
After adding that patch to avoid 'url' overwrites we could use on managed_file:
'#ajax' => [
'url' => Url::fromRoute('profile.basic_form'),
]
-----
In case the patch is not merged and you are having same issue there is a not too fancy work around to deal with this by adding a custom #process using hook_element_info_alter.
/**
* Implements hook_element_info_alter().
*/
function my_module_element_info_alter(&$type)
{
$route_name = \Drupal::routeMatch()->getRouteName();
if ($route_name == 'profile.basic_form'){
if (isset($type['managed_file'])) {
$type['managed_file']["#process"][] = ['Drupal\my_module\Form\BasicForm', 'processManagedFile'];
}
}
}
processManagedFile method on BasicForm:
public static function processManagedFile(&$element, $form_state, &$complete_form) {
$element['upload_button']['#ajax']['url'] = Url::fromRoute('profile.basic_form');
return $element;
}