What is the way to trigger a Drupal form via JavaScript, and pass new values to $form_state while doing so?
I have a main form, which has an element that triggers a jQuery UI dialog with a form in it. When submitting the dialog form, I want to bring the values back into $form_state. I want the main form to display and save the values from both forms. Both Ctools Ajax example and MonoDialog show examples that just manipulate the DOM of the main page/form after submitting a form in a dialog.
One thing I could maybe do is populate a hidden form field with the values from the dialog form in JSON format, and then trigger an ajax button with jQuery. I rather not do this as it doesn’t sound like a clean solution.
What I try to achieve is kind of like the views ui interface, which has a form with form in dialogs. Submitting the dialog forms, updates the main form.
Code example
<?php function example_main_form($form, &$form_state) { // The main form is defined here. Includes a button which triggers a // callback function (example_main_form_callback) to open up a new form // in a dialog popup. Upon this ajax trigger, it also populates $form_state // with some values to pass to the dialog form. } function example_main_form_callback($form, &$form_state) { $commands = array(); // open dialog $commands[] = ajax_command_invoke('#dialog', 'dialog', array('open')); // dialog title $title = t('Configure:') . ' ' . $form_state['dialog']['values']['title']; $commands[] = ajax_command_invoke('#dialog-title', 'html', array($title)); // dialog body $body = drupal_render(drupal_get_form('example_dialog_form', $form_state['dialog'])); $commands[] = ajax_command_invoke('#dialog-body', 'html', array($body)); return array('#type' => 'ajax', '#commands' => $commands); } function example_dialog_form($form, &$form_state) { // include this file in build_info form_load_include($form_state, 'inc', 'example', 'example.forms'); // The popup dialog form is defined here. // the submit button has an ajax callback, which calls // example_dialog_form_callback below. } function example_dialog_form_callback($form, &$form_state) { // This callback closes the dialog, but I also want to populate the // form_state of the main form with the values of this saved form. The values // are available in this callback's $form_state, but I'm not sure what the // best way is to pass them on to the main form. Is it possible to trigger // another form programmatically using jQuery? $commands = array(); // close dialog $commands[] = ajax_command_invoke('#dialog', 'dialog', array('close')); return array('#type' => 'ajax', '#commands' => $commands); }
I think I could attach the dialog form values to the Drupal.ajax.example_element.options.data object. In this way, when the main form is programmatically triggered for an Ajax callback, the values in options.data will be added to the main form $form_state['input']. That’s the cleanest approach I found so far, but still not straightforward. A separate function is required to populate options.data. One options is to extend options.beforeSerialize(), but in my case the Ajax element is dynamic. (See How to extend or "hook" Drupal Form AJAX?) Thus this approach would work better:
In the dialog form callback:
<?php function example_dialog_form_callback($form, &$form_state) { $dialog_id = 'dialog-id'; $commands = array(); // close dialog $commands[] = ajax_command_invoke('#dialog', 'dialog', array('close')); // Call function which attaches the dialog form values to Drupal.ajax.{dialog-id}.options.data. // After triggering the dialog ajax callback, the dialog values will be added to the $form_state of // the main form $data = array( 'id' => $dialog_id, 'values' => $form_state['input'], // for example, but could be cleaned up. ); $commands[] = ajax_command_invoke(NULL, 'dialogValues', array($data)); // trigger dialog button $commands[] = ajax_command_invoke('#' . $dialog_id, 'trigger', array('click')); return array('#type' => 'ajax', '#commands' => $commands); }
The jQuery function:
$.fn.dialogValues = function(data) { // dialog ajax id var dialogAjaxId = data.id; // add values as JSON, so we can pass multi dimensional arrays Drupal.ajax[dialogAjaxId].options.data._dialog_values = JSON.stringify(data.values); };
Is there a better solution?