Hi,
I've been stucked on problem since two weeks.
Basically, what i'am trying to do is:
1) Create a page, in which there is an link ("Click me"),
When i click on it, a form is fetched from another page and added to the current page.
The form is correctly fetched, but it seems any javascript/ajax related to the form is lost.
I have a custom Ajax submit callback for this form, on the page of the form(submit button has class ajax-processed), it is working correctly but when fetched by Ajax(submit button does not has the class ajax-processed), it doesn't.
Below is my code:
<?php
function custom_preprocess_page(&$vars){
drupal_add_library('system', 'drupal.ajax');
drupal_add_library('system', 'drupal.form');
drupal_add_js(drupal_get_path('module','custom').'/custom.js', 'file');
}
/**
* Implements hook_menu
* @return string
*/
function custom_menu() {
$items['my-test/my_form'] = array(
'title' => 'Ajax test',
'description' => 'Page containing form',
'page callback' => '_custom_retrieve_webform',
'access callback' => TRUE,
);
$items['my-test/retrieve_form'] = array(
'title' => 'Ajax test',
'description' => 'Page where form should be loaded by ajax',
'page callback' => '_custom_retrieve_html',
'access callback' => TRUE,
);
return $items;
}
function _custom_retrieve_html(){
return '<div id="justadiv"><a class="clickme">'. t('click me'). '</a></div>';
}
function _custom_retrieve_webform(){
$node = node_load(12);
$submission = (object) array();
$enabled = TRUE;
$preview = FALSE;
$form= drupal_get_form('webform_client_form_12', $node, $submission, $enabled, $preview);
return '<div id="myform">'.drupal_render($form).'<div>';
}
function custom_form_alter(&$form, &$form_state, $form_id) {
if ($form_id == 'webform_client_form_12') {
$nid = $form['#node']->nid;
$form['submitted']['gender']['#default_value'] = 'M';
$form['actions']['submit']['#ajax'] = array(
'callback' => 'mymodule_webform_js_submit',
'wrapper' => 'webform-client-form-' . $nid,
'method' => 'replace',
'effect' => 'fade',
);
//$form['#theme']=array('custom_web_form');
array_unshift($form['#theme'], 'custom_web_form');
}
}
function mymodule_webform_js_submit($form, $form_state) {
// define the $sid variable (submission id from webform)
$sid = $form_state['values']['details']['sid'];
// if we have a sid then we know the form was properly submitted, otherwise, we'll just return the existing $form array
if ($sid) {
dsm($sid);
$confirmation = array(
'#type' => 'markup',
'#markup' => 'sucess',
);
// return the confirmation message
return $confirmation;
}
else {
// return the form
return $form;
}
}
My js:
(function($){
Drupal.behaviors.my_custom= {
attach:function(context,settings){
$('a.clickme').click(function(e){
$('#justadiv').load('/d7/my-test/ajax_loaded #webform-client-form-12', function(response, status, xhr) {
Drupal.attachBehaviors('#webform-client-form-12');
});
Drupal.attachBehaviors($('#webform-client-form-12')[0]);
});
}
}
})(jQuery)
I badly need assistance.
Comments
Have you tried the Ajax
Have you tried the Ajax module?
Custom Code
He want to with custom code not any module.
Varun Kr Pandey
You are on the right track,
You are on the right track, but there are a few issues with your code. First, lets look at your ajax callback function, _custom_retrieve_webform():
The function you've mapped to your AJAX callback path is
_custom_retreive_webform()
. At the end if your function, you've returned some HTML.The code that you return from this function is then wrapped in the page HTML, which includes blocks, content, scripts, css files - everything for an entire page load. The content for that page is
div#myform
, which contains the form that you've rendered. Next, we'll look at your JavaScript:In the above code, when a.clickme is clicked, the jQuery $.load() function requests data from the path
/d7/my-test/ajax_loaded
. The jQuery selector that is attached is then used as a filter, and everything outside this div is stripped off, and thrown away.The problem as you can see, is that a lot of unnecessary HTML is generated on the server, as it is just thrown away by the javascript. To fix this, instead of returning the HTML from your page callback function, you can kill the script right there, as you already have everything you need:
The render() function will render the form and send the HTML to the browser, which means the remainder of the page is not loaded or rendered, so less HTML is sent to the browser, meaning your AJAX responses will be faster as well.
Then, in your JavaScript, you can do the following:
Because your PHP function only returns the form, there is no need to filter anything from the URL you've called. So you can load the entire contents of the response into div#justadiv.
Next, lets look at your usage of Drupal.attachBehaviors():
First, you don't need to pass anything to Drupal.attachBehaviors(). You can, and should, call it with no arguments:
This will allow all modules to attach any behaviors on the new HTML that has been added. Some other module may be specifically watching form elements, and since you have now added form elements, you want to allow all modules to do whatever they want.
The other issue is that you are calling Drupal.attachBehaviors() twice - once when your $.load() function has completed, and once on the $.click() handler you've set on a.askme. This means that every time you click that button, Drupal.attachBehaviors() is called. But you only want to call it when new content has been added, so you should remove your second call to Drupal.attachBehaviors().
One final point on your JavaScript, your $.click() handler will be attached every time Drupal.attachBehaviors() is called. This is no good, as you will end up having your code called multiple times each time the a.askme is clicked. To get around this, you can use Drupal 7's $.once() function. This function ensures that the contained code will only be executed one time. This is achieved by tracking html elements using a custom class name in the HTML (in the following case,
.my-custom
). Here is a bit of a rewrite of your javascript:Finally, lets return back to your menu callback function, as there is one more step that needs to happen for the AJAX on your form to work. You need to generate the javascript settings for the form, and send them to the browser to be merged with the existing settings. Without doing this, any AJAX on your form will not work. Here is the adjusted callback function:
The above merges the returned settings for your form, with the original settings, so that when Drupal.attachBehaviors() is called, your form can be #ajaxified.
Good luck! Code not tested, so there may be typos.
Still no javascript
Thanks for your reply,
The form is returned correctly, but still no javascript related to the form is loaded.
So form is not ajaxified.
here is my ajax response:
Sorry, I had a mistake in my
Sorry, I had a mistake in my code. I cannot edit it now.
This:
Should be this:
And this:
Should be this:
Thanks
It seems to be working,
I probably just need to change the id of my submit button as there is another form in a block on the same page whose submit button has the same id #edit-submit
Great
Great,
It works fine
You are a life saver Jaypan.
Thanks a lot !
jQuery is not defined error
Hi
I have an error: "jQuery is not defined" for the line:
Why is jQuery not defined? The whole page works with jQuery.
I added this to my template.php
The whole code of my Webform
Please can you help me??
<?php$settings = '<script
What is the context of this?
It is also easier to use
It is also easier to use drupal_add_js() to add settings.
Well, the code shown is used
Well, the code shown is used when returning AJAX forms to the browser, so that the ajax-loaded form is ajaxified. But it won't put up an error about jQuery not being loaded, so the poster has done something wrong. But without more code, it's impossible to know what.
If they used a renderable
If they used a renderable array they could use #attached to add the javascript (similar to drupal_add_js())
The code (s)he is using is
The code (s)he is using is sent to the browser in custom ajax callbacks, and has to be run after all content has been rendered. It creates a <script> tag containing all the Drupal.settings for the content rendered in the ajax callback. This script tag then gets appended to the DOM, at which point it merges the new settings with the existing Drupal.settings object. The browser then can call Drupal.attachBehaviors() , and all the new content returned in the ajax callback will have its JavaScript attached through the Drupal.behaviors.MODULENAME.attach().
Core uses this code in ajax_render() for #ajax responses.
Because this code has to be run after all content has been rendered, it cannot be attached using drupal_add_js() or as a render array, as all JavaScript added using these methods has already been rendered, generating the settings that this code then retrieves, generating the <script> tag.
I used the above steps to
I used the above steps to show my login form when user hover over the login link. good thing is that is works perfectly.
Thanks Jaypan
Why would you need to load
Why would you need to load the form via AJAX in that case?
This still does not work for me
The form is not submitted via AJAX. Any help would be appreciated.
Here is my PHP code:
and the JS code:
Should we use die()?
Hi, Jaypan, your solution helped me a lot, thanks. I was wondering if it's better to use
die()
in order to output only the necessary HTML, or is it better to usedelivery callback
in ourhook_menu()
. I chose the latter, I think it's cleaner. I used it to add drupal_get_js() to the output, without which my ajaxed html didn't function.See https://www.drupal.org/node/2046693
Roi
I was wondering if it's
I agree. I've started using that method in the time since I wrote my post.
H
H