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?
ajax_command_invoke
. Thanks :)