Drupal Form API : display the same form again with AJAX, but with different values, on submit

StackOverflow https://stackoverflow.com/questions/14981457

  •  10-03-2022
  •  | 
  •  

سؤال

this is my first post on Stackoverflow, after reading perhaps hundreds of thoughtful questions and no less useful answers.

My point is, today, I never found an (even dirty) way to do what I intend to do, and never managed to find an answer, although it seems quite improbable that no one ever had the same request and/or problem.

Which is, by the way...

Calling the same form again with AJAX, but with different values than those previously entered by the user

The idea

I've got a Drupal Form (a normal form built with Drupal Form API) with textfields and an AJAX-ified submit button. This form is displayed through an AJAX call and is itself AJAX-ified, so.

When I click on 'Submit', I want to do some stuff like looking in the database, updating some values, etc, based on what the user entered in the form. And then, I want to ajax-display the same form again, but with different values than those entered by the user in the first instance of the form.

Everything goes fine with doing whatever I want during the processing, but whatever I do, no matter what, I face the same problem again and again :

The problem

When the new instance of the form is displayed, it is displayed with the previous values (those entered by the user). I never was able to display other values than those previously here in the form when "Submit" was clicked in the previous instance of the form.

Simple example

What I'm actually trying to do is quite complex, with several ajax_commands and a bit of processing, but here is a simpler example that faces exactly the same problem :

function ajax_first_callback_to_my_form($type = 'ajax') {
// here the first instance of the form is ajax-called. No problem with that.

    $mail = 'example@mail.com';
    $first_message = 'Please enter an email address...';

    $commands = array();
    $commands[] = ajax_command_replace('#my_ajax_wrapper', display_my_form($mail, $first_message));
    $page = array('#type' => 'ajax', '#commands' => $commands);
    return($page);

}

function display_my_form($mail, $message) {
// the function used to display the form.
// it can be called by the first ajax callback (the previous function in this example)
// or by the ajax callback triggered by clicking 'submit' on the form itself.

    $form = drupal_get_form('my_form', $mail, $message);

    $display = '<div id="my_ajax_wrapper">';
    $display .= render($form);
    $display .= '</div>';

    return $display;

}

function my_form($form, &$form_state, $mail, $message) {
// the form constructor

    $form = array (
        'email' => array (
            '#type' => 'textfield',
            '#default_value' => $mail,
            '#suffix' => '<div id="my_message">'.$message.'</div>',
        ),
        'submit' => array (
            '#type' => 'submit',
            '#ajax' => array (
                'callback' => 'my_ajax_callback', ),
        ),
    );

}

function my_ajax_callback($form, &$form_state) {
// triggered by clicking 'submit' in the form    

    $mail = $form_state['values']['email'];

    if ($mail == 'correct_mail@gmail.com') {
        $new_mail = 'different_mail@gmail.com';
        $new_message = 'You entered a correct email and here is your new one';
    } else {
        $new_mail = $mail;
        $new_message = 'You entered an incorrect mail, please correct it';
    }

    $commands = array();
    $commands[] = ajax_command_replace('#my_ajax_wrapper', display_my_form($new_mail, $new_message));
    $page = array('#type' => 'ajax', '#commands' => $commands);
    return($page);

}

function my_form_submit($form, &form_state) {
// my_form submit handler

    $form_state['rebuild'] = true; // appears necessary, otherwise won't work at all

}

Okay, it was quite a long piece of code but it seemed useful to fully understand my question.

Processing stuff happens correctly...

All the stuff I want to do in my_form_submit or in my_ajax_callback is properly done. If I check the variables in display_my_form() they are correctly updated.

... but the new instance of the form doesn't take it into account

But whatever I can try, the next time the form is displayed with AJAX, the email field will be 'example@mail.com' as its default value (or any different mail entered by the user), and the message div will be filled with 'Please enter an email address...'.

I tried MANY ways of doing this differently, putting the after-submit processing in the ajax callback, in the my_form_submit function, using $_SESSION variables instead of passing them through the different functions, using the database... None of this works.

What to do ?

Quite annoying. This is not the first time I encountered this problem. Last time I could find a workaround, simply by giving up this idea of re-displaying the same form through AJAX, but now I really would appreciate being able to do this.

Could the problem be related to $form_state['rebuild'] ?

By the way, I'm curious about it : have you encountered this problem before ? Is it something simple which I'm missing out ? If it's a bug, could this bug be Drupal-related, or AJAX-related... ?

Any help or ideas will be truly appreciated. Thank you for your time.

هل كانت مفيدة؟

المحلول

I came up with a solution to this one :

If you are to display the same form again with AJAX, for instance with this function (called by your AJAX callback), no matter what you'll do, it will display the same values again and again :

// It doesn't work :

function display_my_form($mail, $message) {  

    $form = drupal_get_form('my_form', $mail, $message);

    $display = '<div id="my_ajax_wrapper">';
    $display .= render($form);
    $display .= '</div>';

    return $display;
}

If you want to change the fields values when refreshing the form, you have to update the form manually, after having called it again, by adding this kind of line :

// It works :

function display_my_form($mail, $message) {

    $form = drupal_get_form('my_form', $mail, $message); // $variables are simply ignored if the form is already displayed. Rebuilding it won't change a thing.

    $form['email']['#default_value'] = $mail; // update a part of the form
    $form['email']['#suffix'] = $message; // update another part of the form

    $display = '<div id="my_ajax_wrapper">';
    $display .= render($form);
    $display .= '</div>';

    return $display; // sends $display to our AJAX callback, and everything's fine now

}

Contrary to easy belief one (such as... me) can first have about it, the form doesn't take into account the variables it's being sent with drupal_get_form, when already constructed and recalled by AJAX.

It's just not enough to update the variables, and do drupal_get_form again. You have to do drupal_get_form, and afterwards manually update the parts of the form you want updated.

Hope this will help someone.

نصائح أخرى

Well I am quite confident about your issue if this is the case:

$commands[] = ajax_command_replace('#my_ajax_wrapper', display_my_form($new_mail, $new_message));

The problem is not anything else its just the id you are passing.You need a class and not the id "#my_ajax_wrapper", because id might get changed but class won't in this case. Try with this you should get the result as you want.

Note: to make it work, one needs to add this in form_submit handler:

function my_form_submit($form, &$form_state)
{
    $form_state['rebuild'] = true;
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top