When you use AHAH buttons to update (pieces of) a form, and the replaced markup (the data returned by the callback function) contains new AHAH buttons, the AHAH behaviors are not attached to these new buttons. This is caused because the ahah behavior uses Drupal.settings to loop through all AHAH buttons. While each AHAH button has a bunch of settings attached, using Drupal.settings is preferred over using $('.classname:not(..)').each(...., which is a more common way to attach behaviors.
If the AHAH does it's request, and the callback function is built, AHAH creates a new Drupal.settings object in the background, containing all (new) AHAH buttons.
Currently you need to call drupal_add_js() and add $javascript['setting'] to the response function's output in order to make this work.
How about rewriting the Drupal.settings object by default after each AHAH request?
Comment | File | Size | Author |
---|---|---|---|
#14 | patch_drupal_ahah_attach_settings.patch | 1.9 KB | enikola |
#9 | ahah_attach_settings.patch | 577 bytes | Pedro Lozano |
#2 | ahah_attach_settings.patch | 755 bytes | quicksketch |
Comments
Comment #1
skilip CreditAttribution: skilip commentedComment #2
quicksketchThis is immensely important. We made provisions for this exact functionality in #360081: Pass Settings Locally to JS Behaviors. Now we just need to actually use it. However rather than recreating the global Drupal.settings.* after each AHAH request, we're taking the safer route of leaving the original variable in-tact (in case items on the page continue to be dependent on them), and passing a new settings variable locally to all the behaviors.
This patch simply makes ahah.js use this feature that we put in place for this exact purpose.
Comment #3
RobLoachHitting up some tagination.
Comment #4
sunThis patch makes absolutely sense.
I've tested this patch manually by uploading/re-ordering files and running batches. All works fine.
Well, all works fine regarding this patch... apparently, each file upload via AHAH throws a load of PHP notices (also without this patch), not affecting the functionality, i.e. just silly variable usage without testing whether array keys actually exist. To be fixed elsewhere.
Ready to go.
Comment #5
sunDidn't mean to remove issue tags.
Comment #6
Dries CreditAttribution: Dries commentedGreat. Committed to CVS HEAD.
Does that mean we can clean-up some code in core?
Comment #7
quicksketchYes, some followup issues will probably be necessary. This particular issue was going to be blocking a File Field in core, since I needed an AHAH "Remove" button to show up after clicking the AHAH "Upload" button (so AHAH behaviors inside of returned HTML). There aren't any places in particular that *need* this functionality yet, but book.module might be a good candidate, or the drill-down menu selectors.
We'll probably finish off #399982: Simplify and standardize returning an AHAH response before beginning cleanup, since it should reduce a lot of duplicated code. Thanks Dries, I'll be posting what I have so far on the File Field issue soon.
Comment #9
Pedro Lozano CreditAttribution: Pedro Lozano commentedWhy isn't this in D6? I just used the code from quicktabs module.
Comment #10
enikola CreditAttribution: enikola commentedI see the solution proposed by quicksketch (#2) is in D7. My question is: are there any plans for this to be backported to D6?
Comment #11
quicksketchIt's not (and won't be) in Drupal 6 because it's an API change. We can't have modules all of a sudden requiring "Drupal 6.17 or higher", because they are dependent on this functionality. Anything that is written for Drupal 6 should work with all versions of it.
Comment #12
enikola CreditAttribution: enikola commentedUnfortunately the patch isn't complete, drupal.js must also be patched. I'll be able to upload a patch for testing tomorrow.
edit: Oh, sorry, I should refresh the page before posting again.
I see, it makes sense. I think the patch would be still interesting for many people though. Where should I post it, in this thread or should I open a new one?
Comment #13
sunYou surely can attach further patches here, but please keep the issue closed. However, one of the previous follow-ups mentioned that a solution for this exists in the quicktabs module.
Comment #14
enikola CreditAttribution: enikola commentedHere is a working patch against 6.16 that takes quicksketch (#2) approach for reattaching behaviours by providing new settings object rather than modifying the global one, in case other JS rely on it.
Example:
Comment #15
etisbew CreditAttribution: etisbew commentedI have applied the patch that you provided in the context below. see the code. I have no luck. I appreciate your further help. thanks.
Below is my code please check and let me know your suggestions.
function add_loyalty(){
global $user;
$period = _get_loyalty_programs();
// This is the event to change the list box values
$form['loyalty']['program'] = array(
'#type' => 'select',
'#default' => 0,
'#options' => $period,
'#ahah' => array(
'event' => 'change',
'path' => 'program/status_js',
'wrapper' => 'target',
)
);
//$pstatus = array(0 => 'Select Your Status', '1' => 'No Status','2'=>'Silver','3'=>'Gold','4'=>'Platinum','5'=>'Elite','6'=>'Executive Platinum','7'=>'Premier','8'=>'Premier Executive');
// Here render the list box dynamically
$form['loyalty']['pstatus'] = array(
'#type' => 'select',
'#title' => 'Program Status',
'#prefix' => '',
'#options'=>array(0 => 'Select Your Status'),
'#suffix' => ''
);
$lstatus = array(0 => '0 year', '1' => '1 year','2'=>'2 year','3'=>'3 year','4'=>'4 year','5'=>'5 year','6'=>'6 year','7'=>'7 year','8'=>'8 year','9'=>'9 year','10'=>'>=10 Years');
$form['loyalty']['lstatus'] = array(
'#type' => 'select',
'#title' => 'Length of current Status',
'#options' => $lstatus,
);
$fredumption = array('1' => '1 per year','2'=>'2 per year','3'=>'3 per year','4'=>'4 per year','5'=>'5 per year','6'=>'6 per year','7'=>'7 per year','8'=>'8 per year','9'=>'9 per year','10'=>'10 per year');
$form['loyalty']['fredumption'] = array(
'#type' => 'select',
'#title' => 'Frequency of redemption',
'#options' => $fredumption ,
);
$elength = array('1' => '1 year','2'=>'2 years','3'=>'3 years','4'=>'4 years','5'=>'5 years','6'=>'6 years','7'=>'7 years','8'=>'8 years','9'=>'9 years','10'=>'>=10 years');
$form['loyalty']['elength'] = array(
'#type' => 'select',
'#title' => 'Enrollment Length',
'#options' => $elength,
);
$form[loyalty]['uname'] = array(
'#type' => 'textfield',
'#title' => t('User Name'),
'#size' => 30,
'#maxlength' => 64,
);
$form[loyalty]['pword'] = array(
'#type' => 'password',
'#title' => t('Password'),
'#size' => 30,
'#maxlength' => 64,
);
$form[loyalty]['account_number'] = array(
'#type' => 'textfield',
'#title' => t('Account Number'),
'#size' => 30,
'#maxlength' => 64,
);
$form['#redirect'] = 'loyalty/flash';
$form['submit']=array(
'#type'=>'submit',
'#value'=>t('Add It')
);
return $form;
}
// Change program status list biox values dynamically with ahah interface
function program_status_js() {
$form_state = array('storage' => NULL, 'submitted' => FALSE);
$form_build_id = $_POST['form_build_id'];
// Get the form from the cache.
$form = form_get_cache($form_build_id, $form_state);
$args = $form['#parameters'];
$form_id = array_shift($args);
// We will run some of the submit handlers so we need to disable redirecting.
//$form['#redirect'] = FALSE;
// We need to process the form, prepare for that by setting a few internals
// variables.
$form['#post'] = $_POST;
$form['#programmed'] = $form['#redirect'] = FALSE;
$form_state['post'] = $_POST;
// Build, validate and if possible, submit the form.
drupal_process_form($form_id, $form, $form_state);
// This call recreates the form relying solely on the form_state that the
// drupal_process_form set up.
// Render the new output.
$replacement['#type'] = 'select';
$replacement['#title'] = 'Program Status';
$replacement['#id'] = 'edit-pstatus';
$replacement['#name'] = 'pstatus1';
$psquery = "SELECT node.nid AS nid,
node.title AS title,
node_data_field_program_status_value.field_program_status_value_value AS ps_value,
node_node_data_field_loyalty_programs.nid AS ps_nid,
node.title AS node_title
FROM node node
LEFT JOIN content_field_loyalty_programs node_data_field_loyalty_programs ON node.vid = node_data_field_loyalty_programs.vid
LEFT JOIN node node_node_data_field_loyalty_programs ON node_data_field_loyalty_programs.field_loyalty_programs_nid = node_node_data_field_loyalty_programs.nid
LEFT JOIN content_type_program_status node_data_field_program_status_value ON node.vid = node_data_field_program_status_value.vid
WHERE (node.type in ('program_status')) AND (node_data_field_loyalty_programs.field_loyalty_programs_nid = {$form_state['values']['program']})";
$psres = db_query($psquery);
$replacement['#options'][0]='Select Your Status';
while($row = db_fetch_object($psres)){
$replacement['#options'][check_plain(trim($row->nid))]=check_plain(trim($row->title));
}
/*$replacement['#attributes'] = array(
'id' => 'edit-pstatus',
'class' => 'ahah-processed',
'name' => 'pstatus',
);*/
//$replacement['#options'][1]='sample2';
$form = drupal_rebuild_form($form_id, $form_state, $args, $form_build_id);
$output = drupal_render($replacement);
form_set_error(NULL, '', TRUE); // remove CSS error styles
drupal_get_messages(); // remove all messages
// unset($choice_form['#prefix'], $choice_form['#suffix']); // Prevent duplicate wrappers.
//$output = drupal_render($choice_form);
drupal_json(array('status' => TRUE, 'data' => $output));
}
Thanks
Comment #16
duckzland CreditAttribution: duckzland commentedI'm facing similar problem countless of time while building a module, and seems the problem is fixed by including / calling quicktabs_ahah.js.
Comment #17
siramsay CreditAttribution: siramsay commentedHello, sorry if I've missed something here but duckzland, how do you include or call quicktabs_ahah.js ?
thanks
Comment #18
siramsay CreditAttribution: siramsay commentedComment #19
duckzland CreditAttribution: duckzland commenteduse drupal_add_js() function and point the path to quicktabs_ahah.js or simply copy the quicktabs_ahah.js to the custom module and point drupal_add_js() there
Comment #20
siramsay CreditAttribution: siramsay commentedthanks, still stuck or something else is wrong
this is the add js I used drupal_add_js(drupal_get_path('module','MYMODULE') . 'quicktabs_ahah.js' );
I placed it at the beginning of the module. is that the correct place?
Comment #21
duckzland CreditAttribution: duckzland commentedif you copy the quicktabs_ahah.js to your module then :
should load the js, you can check in firebug to see if the js is loaded or not though.
Comment #22
siramsay CreditAttribution: siramsay commentedthanks!! that is what I had including the / before the quick tabs, firebug actually shows that it is loaded
here is the script I have, it is from this tutorial on how to add fields http://jamestombs.co.uk/2010-07-08/adding-additional-form-elements-using...
maybe something else wrong in the code? remove button?
Comment #23
wasiabbas CreditAttribution: wasiabbas commentedNo need of patch to extend the drupal.settings object. just simply output the ahah response like this.
but all this solution is not useful because the JavaScript array that has been built so far for $scope is returned by drupal_add_js() function. so the existing buttons path are generates, doesnt rebuild the js.
let me know if anyone has a solution to generate the fresh javascript array.
Thanks.