Hi,
I would like to attach a zip file containing two example modules to the Doing AHAH Correctly in Drupal 6 page (http://drupal.org/node/331941). It would be nice if I got a go from some documentation guru and a quick review of my code to make sure it's okay.
AHAH is a confusing topic and it took me the better part of a week to grasp the concepts behind it. The handbook page wasn't very helpful. If you browse through the comments, a lot of questions remain unanswered and some suggestions are downright wrong.
The package contains two modules that demo basic AHAH principles:
A. Button demo module
Demonstrates an implementation of AHAH based on a submit button.
B. Select demo module
Demonstrates an implementation of AHAH based on a select list.
Both modules contain comments which explain what happens through the process.
Package attached to this issue.
Comment | File | Size | Author |
---|---|---|---|
#14 | category_subcategory_select_fields.txt | 3.51 KB | WildKitten |
#14 | taxonomy_cck_fields_with_ahah.txt | 4.98 KB | WildKitten |
ahah_example.zip | 14.69 KB | netsensei |
Comments
Comment #1
WildKitten CreditAttribution: WildKitten commentedGreat examples. I just have to ask you, do you know how to add those 2 select fields to existing form, in ahah_example_select_form_alter?
Cause when I do this:
I loose all data that have been already in $form.
Comment #2
greg.harveyNo time today, but will look at these ASAP. Subscribing to remind me to come back later. =)
Comment #3
asmdec CreditAttribution: asmdec commentedThis code works fine with simple forms, but when you have some more fields or required fields some problems happen.
I have a form with 4 fields, 2 hierarquical selects and 2 required textfields (title and body). When the value of first select changes, the second select doesn't update, instead I receive a message to correct the required fields (title and body).
I think that some validations should not happen during AHAH callbacks. How could I disable this validations?
I remove the
theme('status_messages')
from JSON return and when the form is posted I receive the unecessary messages.Sorry for my bad english :P
Comment #4
netsensei CreditAttribution: netsensei commentedWell, these are just two textbook examples that show the basic principles behind AHAH.
I suppose you're trying to add AHAH to a node form. Maybe you should check out this handbook page:
http://drupal.org/node/331941
Consider the AHAH cycle it describes. Between steps 4 and 5, you could alter the $form array and set #required on both the title and body fields to FALSE. Maybe that would make it work.
Comment #5
WildKitten CreditAttribution: WildKitten commentedI just manage to make it (2 select fields in form_alter) with ahah. I'm close to my deadline (with clients), but I'll give my best to post my solution in next week.
Comment #6
asmdec CreditAttribution: asmdec commentedI'm using the following code to remove the messages and CSS error styles before
drupal_json
is called.It works, but if I could skip validations instead of just hide them, would be nice :)
Comment #7
asmdec CreditAttribution: asmdec commentedI don't understand how the callback of
type_submit
button is called on change event of thetype
select.Please, anyone could explain?
Comment #8
asmdec CreditAttribution: asmdec commentedReading "Forms API Quickstart Guide" in "Submitting Forms" I figured it out.
The data I was posting to my form was not valid (title and/or body required fields are empty) and the flow was not passing to the
type_submit
submit function breaking the flow, and theanimals_kind
select wasn't updated.Comment #9
asmdec CreditAttribution: asmdec commentednetsensei,
setting the
#required
attribute of required fields toFALSE
, works very nice.I think that's a missing functionality to skip validations instead of doing this work in all fields that have some validation rule that can cause this effect, right?
Comment #10
netsensei CreditAttribution: netsensei commentedAsmdec,
It's not really a case of "missing" functionality here. AHAH functionality in Drupal provides you with several hooks where you should implement your own code. The problem is that it's not very well documented what you can and can't do.
Altering the #required attribute in the AHAH callback shouldn't pose a security risk (can someone confirm this?) because the data is just copied to the $form_state variable. It's used to repopulate the form when it's re-rendered with the changed elements.
If you would submit your entire form for further processing, you should be getting a validation error when a required field wasn't filled out.
oboskovic,
I saw your form topic but didn't have much time to give you an entire answer. Using form_alter in a seperate module to give existing fields the AHAH attribute would be my strategy too. I would then implement the required submit handlers and the AHAH call to make it all work in this module. You should pay attention to the naming of your functions and the callbacks. It's easy to make a mistake and AHAH is hard to debug.
I saw your comments on http://drupal.org/node/331941#comment-1503260. This code is using the 'wrong' way as Kat Bailey points out. It's changing the form directly in the AHAH call (mymodule_change_flower() function) and that's just, well, plain wrong. The callback is used to get the data into $form_state and call the submit handlers. Changes to the form happen in the mymodule_form rendering form itself. Or in form_alter in your case.
--
Colada | http://www.colada.be
Comment #11
asmdec CreditAttribution: asmdec commentedNetsensei,
I appreciate your help and understand your effort to better document AHAH for developers to know exactly what they're doing. Perhaps I don't use the right word when I say "missing" (bad english :), sorry.
I think that this "missing" functionality is (could be) in Form API, in
drupal_process_form
more exactly. It would receive some parameters that indicates that validation is not needed.Hierarquical selects (i.e.) don't need to validate the entire data of the form to populate one element. We're thinking only in #required validator, but we have many other validators that need to be disabled as well, like mail validator, user-defined validators, etc.
In the case of not valid data posted to form, could I call
form_execute_handlers('submit', $form, $form_state)
after step #5 (drupal_process_form call)?Sorry if my ideas are confused, I'm learning AHAH these days and I don't have very deep knowledge so.
Comment #12
asmdec CreditAttribution: asmdec commentedI'm having another kind of bug now, the same as (not)discussed in http://drupal.org/node/371339.
1/ im creating a new node
2/ im using ahah to change a value
3/ i submit the form without filling mandatory fields
4/ so i have a new page telling me "missing fields..." and now with the new node form, the main form "action" is set to the ahah submit url
You know any about this??
Comment #13
greg.harvey@asmdec, just do a drupal_get_messages() call after right at the end of your callback function and it will clear out any messages set during the node form validation that don't apply at this point. =)
Comment #14
WildKitten CreditAttribution: WildKitten commentedI make 2 files for everyone how needs 2 select fields (like country and city, or category and subcategory), in form_alter(). First file shows an ordinary , custom fields added in some content_type by form_alter function.
And second file shows how to change 2 cck fields into 2 select fields with ahah. More specific , it is a workaround for Hierarchical Select fields in some content type. I had to solve this problem fast, and this was the only solution after 10 days of research. It is not nice, but it works.
I made content type with 2 text fields called: field_category and field_subcategory. I made taxonomy Location, that has depth 2. (I mean it has Countries and Cities items). In form_alert function I made 2 dummy fields called: category and subcategory. They are select fields , and they are made with ahah, to replace Hiearachical select fields. I also didn't give any permission for cck fields, it means, admin is the only one who can see it.
The script works like this: you chose category, then ahah display subcategory for that category, and when you click on save/submit, you trigger JS that puts those values in corresponding cck fields field_category and field_subcategory. This way, drupal insert/edit/update all data by himself (you don't need to write code for that). That is all.
JS on the end of second file should be put in page.tpl.php.
I was in hurry so sorry if there are some minor mistakes.
Comment #15
netsensei CreditAttribution: netsensei commentedWell I spent an hour or so to fit the code from my select example in a CCK form with hook_form_alter.
I'm faced with the same issues:
* If a required field isn't filled, it complains.
* After an AHAH call, the form action is changed to something else and the data isn't saved in a new node.
I'm going to delve a bit deeper in this and see what I can do to make it work.
--
Colada | http://www.colada.be
Comment #16
asmdec CreditAttribution: asmdec commentedThe
#action
attribute is altered by default form element information provided in hook_elements hook on system module:request_uri
is returning the uri called via AHAH in this case. It happens indrupal_rebuild_form
call, wich callsdrupal_prepare_form
, wich calls _element_info('form'), wich invokes the hook_elements hook and set the#action
as the uri requested by AHAH.I'm setting manually the
#action
attribute.Comment #17
creazion_dev CreditAttribution: creazion_dev commentedThx. You made my day.
Comment #18
Edward.H CreditAttribution: Edward.H commentedthanks,You are a star!
Comment #19
cfmcoder CreditAttribution: cfmcoder commentedThe example code for select works for Firefox, but fails for IE6 and IE7. When the first select is chosen, the second select does not appear. Any ideas?
Comment #20
himerus CreditAttribution: himerus commentedI've noticed a couple things on my own implementation. Some have already been mentioned here.
In order to prevent issues with multiple validations (form validate works once, then the #action url is reset to the callback rather than the correct one, so the #action parameter needs to be manually set using:
Rather than CSS'ing out the extra submit button, it is more appropriate to use #access = FALSE to avoid it rendering. The callback is still registered, and will be used during submission of the select element
Also, regarding having the validation callbacks called when the AHAH element is submitted, I only found one clean option.
I've avoided using #required = TRUE, even on the fields I do require. What I have done also in my validate callback for the main form is to check to ensure the appropriate button was used for the callback, in most default cases the #id is edit-submit
This really is a great piece of documentation. Needless to say the AHAH implementations are confusing at best, and this goes a little way further to a better understanding for myself personally.
I'll say it's not perfect, but it is a BIG step towards a more usable explanation. Thanks for the work!!
Comment #21
himerus CreditAttribution: himerus commentedMy bad, accidentally reset title, changing back.
Comment #22
TwoDI have recently been trying to restructure a module's AHAH handling and wondered why none of my code worked while examples like the ones provided in ahah_example.zip did, especially the one with selects. So, I stepped through the code using a debugger and tried to carefully take notes of what happened, and here are the results:
The select example in the provided ahah_example.zip relies on a workaround for an IE behavior/bug and is easily broken.
The only reason the ahah_example_select_type_submit handler is called instead of none at all is that includes/form.inc has _form_builder_ie_cleanup($form, &$form_state). It is designed to identify the case where IE does not pass information about the clicked button in the POST data, because there was only one button present and the enter key was used to submit the form. This case is very similar to when a changed select was used to trigger an AHAH POST.
_form_builder_ie_cleanup($form, &$form_state) will always set the first button encountered as the 'clicked' button and use its submit handlers if no button has already been identified.
To confirm this, insert a
return;
at the top of _form_builder_ie_cleanup($form, &$form_state), or make sure it's not called when running the example. No submit handler will run when AHAH is triggered via the first select, so the second select will always be replaced by its default state.If the Save button is simply moved before the "Submit the type" button in the code, the form will be passed through its submit handler instead and the result is rather confusing...
If more than one #ahah-select is present in the form, and they all use an extra button for their submit handlers, only the first encountered submit handler will ever be run regardless of which select is changed.
Adding #ahah-selects like this via hook_form_alter will not work as intended because the original form's Submit button will be encountered before the button added by the form altering implementation. This is most likely to cause the form values to be saved to the database "behind the user's back" (if they happen to validate).
I have come up with a few workarounds for this, but I have only partially tested them. The first is to actually use the extra button, introduced to hold the #submit handler and just move the #ahah stuff from the select to it. If we really want the select to do stuff when changed, use a JavaScript to simulate a click on the #ahah-button. The 'ajaxSend' and 'ajaxComplete' events from jQuery could be used to disable and re-enable the select so it can't be clicked during a request.
We could also keep the #ahah stuff on the select and use jQuery's 'ajaxSend' event to inject the POST data which would have been created if the extra button had been clicked. The 'ajaxStart' event is global and is sent a reference to the URL and serialized form data so we can listen to it from anywhere and manipulate the data without risking other AJAX functionality being disturbed. Just note that if the form is re-serialized using .formSerialize() from jquery.form.js, one must first enable the select or its value will not be included, then disable it again as it will be automatically re-enabled when the request completes. The disabling/enabling flicker on the elements should be hardly noticeable.
Comment #23
arianek CreditAttribution: arianek commentedHey, if you see any of this info as useful additions to the current AHAH section of the handbook, please do add it! http://drupal.org/node/348475 you can set the issue status to "needs review" if you've made changes and would like the docs team to review the formatting, etc. Thx!
Comment #24
netsensei CreditAttribution: netsensei commentedYes. I've written the modules a few months ago. In the mean time, I got a chance to delve quite deep into this. The messy execution of submit handlers really is a problem.
A good help is Wim Leers' AHAH helper module. About the problem you describe, I find this in the comments:
So you should be able to get it to work by setting this variable in your AHAH callback function.
Comment #25
beowulf1416 CreditAttribution: beowulf1416 commentedadditionally, I add a handler to the jquery ajaxStop event so I can clear the errors that are set on the form.
Comment #26
cibonato CreditAttribution: cibonato commentedIt's exactly the very same problem I'm dealing with right now. I have a custom content type created through Drupal web interface and it has some CCK fields. I can alter it using hook_alter_form() (I created a custom module to do it). So, I'm using the hidden button approach to solve the problem AHAH + select list, but the only submit handler executed is that bound to Save button.
Maybe it could sound too naive, but is not it possible to put this hidden button before the Save button through hook_alter_form()?
Greetings..
Comment #27
cibonato CreditAttribution: cibonato commentedIf I set $form_state['submitted'] = TRUE then nothing happens and some debug could confirm that no submit handler is executed at all when the select list change.
I'd like to post this comment as a matter of feedback.
Greetings.
Comment #28
joachim CreditAttribution: joachim commentedThese example modules should perhaps be submitted / merged into http://drupal.org/project/examples
Comment #29
greg.harveyThere are already AHAH examples for Drupal 6 in the Examples module, according to the project page. I have never reviewed/compared them to the discussion here.
Comment #30
joachim CreditAttribution: joachim commentedWould probably be best to merge into the examples module, and then put a link in documentation to the project page. That way we avoid duplication; and development of the examples has its own issue queue, repository, etc.
Comment #31
arianek CreditAttribution: arianek commentedmoving this to AHAH queue... not sure whether this needs vetting...
Comment #32
webchickAHAH Helper is actually just a contrib module. These comments seem to be about a page referencing Drupal core's handbook docs about core's AHAH library, not AHAH Helper module, so restoring back to the Documentation queue. Sorry if this is incorrect.
Comment #33
ookami.kb CreditAttribution: ookami.kb commentedI've tried to write a code with this example, but i've encountered one problem. When I submit form without AHAH it works normal, but if i submit it with AHAH, the data in first select ('kind' property is not saved even in $_POST - drupal does not send it)
Comment #34
PrplPplEtr CreditAttribution: PrplPplEtr commented...not sure if something has changed in core since this was posted, but these examples seem to be broken. The modules install fine, and I can view the form examples, but, regardless of whether I use "button" or "select", the second select not only doesn't update when the first is changed, it simply disappears.
Comment #35
jhodgdonActually, arianek's suggestion was to get this into the Examples project, so let's try that.
Comment #36
rfaySo I haven't looked at these (didn't know about this thread) but does the D6 ahah_example not cover this material?
I should note that if this uses ahah_helper, it wouldn't be a candidate for Examples because we only do core stuff. (Just have to draw a line somewhere....)
Comment #37
Mile23Comment #38
Mile23It's end-of-life time for the 6.x-1.x branch of Examples. See #2642596: D6, D7 Roadmap for Examples