0

I have a link in a block and when i click it it brings with ajax a form from another page let's call it contact. In contact page the form uses ajax to submit the data, it works ok. But when i get the form by clicking that link in another page using ajax the form loses the ajax submit. and instead it redirects me to the contact page.

How can i keep the ajax submit even if the form loads with ajax in another page???

4 Answers 4

2

It seems, I found some solution, may be not fully drupal-way.

Firstly, we need to load JS libraries, needed for working of ajax submit. This code helps us:

drupal_add_library('system', 'drupal.ajax');
drupal_add_library('system', 'drupal.form');
drupal_add_library('system', 'jquery.form');
drupal_add_library('system', 'druapl.progress');
drupal_add_library('system', 'drupal.textarea');

Nextly, we need to fill JS class Drupal.settings.ajax with data about page elements, which provides ajax behavior. I have not an universal solution, I only stops JS code on breakpoint in misc/ajax.js when running it on page with correct working ajax form. You can see correct values in this part of code:

Drupal.behaviors.AJAX = {
  attach: function (context, settings) {
    // Load all Ajax behaviors specified in the settings.
    for (var base in settings.ajax) {
      if (!$('#' + base + '.ajax-processed').length) {
        var element_settings = settings.ajax[base];

        if (typeof element_settings.selector == 'undefined') {
          element_settings.selector = '#' + base;
        }
        $(element_settings.selector).each(function () {
          element_settings.element = this;
          Drupal.ajax[base] = new Drupal.ajax(base, this, element_settings);
        });

        $('#' + base).addClass('ajax-processed');
      }
    }

So, in my case resulting JS code, needed to be added into startup javascript, looks like this:

if(Drupal.settings.ajax == undefined){
    Drupal.settings.ajax = {
        'edit-submit': {
            callback: "faqform_ajaxsubmit",
            event: "mousedown",
            keypress: true,
            prevent: 'key',
            submit: {
                _triggering_element_name: "op",
                _triggering_element_value: "Send"
            },
            url: 'system/ajax',
            wrapper:'submit-message'
        }
    };
}

If all done correctly, you form, loaded by ajax, will have correct ajax behavior, in my case - ajax submit.

May be there are more graceful solutions, may be diving deeper into code will help you to find them.


So, here is much more graceful solution!

After some analyses of steps, maked above, I decided, that only thing we need to make ajax form, loaded by ajax, to work is fill javascript Drupal.settings array with correct data, describing forb behavior. In the above example we made it by hands, with hardcode, whitch is not true. Obviously, somewhere in drupal code it work does automatically. I found this place. It is function ajax_pre_render_element in the ajax.inc. It gives array of any form element with ajax property and appends to it additional parameters, which will be converted to JS code and added to Drupal.settings array later. Exactly thing, that we need.

Here is my code now:

function anyform_block_info() 
{
    //standart form for displaying to user
    $blocks['any_form'] = array(
        'info' => t('Any form'),
        'status' => true,
        'region' => 'content',
        'weight' => 99,
        'visibility' => 1
    );
    //hidden 'form' needed to generate and load ajax behavior settings before form loading
    $blocks['faq_form_hidden'] = array(
        'info' => t('Any fake form'),
        'status' => true,
        'region' => 'footer', //I thing, it will be better place it in footer^ in my case content is ajaxed
        'weight' => 99,
        'visibility' => 1
    );
    return $blocks;
}

function anyform_block_view($delta) 
{
    switch ($delta) {
        case 'faq_form':
            $block['content'] = drupal_get_form('anyform'); //standart form
            return $block;
        case 'faq_form_hidden':
            $block['content'] = anyform_get_hidden_form(); //fake form
            return $block;
        break;
    }
}

function anyform_get_hidden_form()
{
    $form = drupal_get_form('faqform'); //give our original form
    $form = ajax_pre_render_element($form['submit']); //create settings for element with #ajax property (don't pass whole form as argument - not works)

    //makes fake form with hidden element in footer, but with correct array with settings for ajax behavior
    $fakeform['fakeform'] = array(
        '#type'=>'markup',
        '#markup'=>'<div style="display: none;"></div>',
        '#attached'=>$form['#attached'], //our magical array
    );

    return $fakeform;
}

So, I hope, it will solve most of your problems with drupal ajax-loaded forms. For me this solution works without any problems, and I going sleep being happy =^_^= Good luck!

5
  • Thank you for sharing your code. I'll try this when i find some time and then I'll post back the results
    – dianikol
    Mar 16, 2012 at 0:17
  • Disadvantage of this approach is that you always need to rewrite your php form code to js code. For example, if you need to add any settings to form... you need also add it in you js hack code =\ Sure, it is not true way...
    – ASGAlex
    Mar 17, 2012 at 17:30
  • Hmm, it seems, that I found one good solution - post updated. Hope, it helps =)
    – ASGAlex
    Mar 21, 2012 at 22:47
  • It seems that ajax_pre_render_element() is the key. Right? Is it necessary to create the $fakeform array? Isn't enough just to return the $form variable?
    – dianikol
    Mar 22, 2012 at 16:47
  • Yes, it is necessary, because something HTML with javascript bindings must be rendered. If nothing will be rendered, needed drupal libraries will not be loaded, needed javascript settings will not be created, and when your form will be loaded, behaviors will not be attached. In my case ajax form is shown only in one page, which is loaded by ajax. On all other pages the fake form is shown. Advantages? You have clean pages without a lot of hidden and may be not needed content. Forms are loaded only when needed, not always.
    – ASGAlex
    Mar 22, 2012 at 20:30
1

Ah.

It's a DOM thing. When you get the new contact form back (rendered via AJAX), then you have to tell the new button (in that rendered block), to issue another AJAX request -- otherwise it does it's default behavior.

-- EDIT --

What you do is embed a tag IN the form itself. When that form gets called into the DOM (via the AJAX call), the script should re-instantiate the button as an ajax button. In jquery:

<script>
$().ready(function(){
    $('.button').click(function(){
        // submit form via AJAX
        return false;
    });
)};
</script>
3
  • 1
    Yes that makes sense. The problem is how can i do that in a form since it uses form api to add ajax functionality. For example in this form i have a field that when i click it a calendar pops up no problem because i use Drpal.attachBehviours in my js file. What is the way to do that in a form button?
    – dianikol
    Sep 23, 2011 at 4:33
  • edited my reply
    – jhchnc
    Sep 23, 2011 at 14:55
  • Of course i will mark your answer!! But the form submits using the '#ajax'property when i built the form. So the javascript is handled by drupal itself. I'm not sure what ajax call i should put in the sript above. Here you can see what's going on here Just the click the link at the top "Click me" to see it in action
    – dianikol
    Sep 23, 2011 at 16:03
0

I've run into this problem before...I was able to get it working by loading the form in an i-frame that is in the modal window. You can set a redirect with some simple javascript in the header of the from. Doing it this way will also keep the error messages in the modal box if the form doesn't validate.

1
  • Thank you for your answer. I don't think iframes used for this purpose anymore.There is got to be a native solution for this..
    – dianikol
    Sep 24, 2011 at 7:25
0

developed a custom module to make ajax things easier.. with this module you can load any pages without breaking its ajax or any other javascript/jquery functionality , this is done using Drupal.attachBehaviors .

here is the module (currently under review process)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.