You are here

I need to create a pair of dynamically interacting selects. The content in the actual exposed filter needs to be grouped, so i added a select with the group names that should, on change, load the coresponding items in the second select (the exposed filter).

I used hook_form_alter to add the select that triggers the ajax call.
My problem is that the ajax call does not trigger the callback function. I tested the same code in the form_alter of a node's add page, and they work correctly.
Any suggestions?

Comments

First problem: views preprocesses only the filters defined and exposed, ignoring all other widgets. The result is that the "form_id", "form_build_id" and "form_token" did not make it into the form, so the ajax call was incomplete. I added them to the #info array, so they would be rendered as filters.

Second problem. They arrive in the preprocess function with the #access set to false. I hacked it to set it to true, and it worked. Now the ajax works.

Current problem: Filtering no longer works. The list loads correctly, but when I click the filter button, even without setting any filter, there are no results. If I just comment the #ajax part for the widget I added then it all works, so it's not an issue with the newly added filters but rather with the js. I'm stuck again :(

Views are $_GET forms and they specifically remove the form_id and form_build_id and form_token because they are 'submitted' even when they aren't submitted. That means the standard #ajax tools don't work with them, since those rely on being able to cache the form in core's form cache. That system is to naive to work with core's filters. I've never really tried to do anything like this in D7 yet, so I don't know what the solutions might be, but I can say that it's going to provide very ugly URLs if you hack the form id back in.

Ok, I made it work.
@merlinofchaos, I would love to read your comments on this idea. Maybe it can be implemented in a cleaner way inside views.

So. The only problem was that the ajax call needs form information in order to work (access form from cache) while views needs that information omitted (access form NOT from cache). My solution was to add an invisible and disabled select with all info in it, then add the info when ajax is called.

This way, if an ajax call gets made, the form info gets submited, while views' exposed filters stay clean.

One last note: in the ajax tutorial they tell you to expect the submited values in $form_state['values']. That is true for the ajax call, but if you just submit the exposed filters form, the values are in $form_state['input']. So you should do something like this:

Perfect! Thank you very much for this. I was able to get my form_alter and Ajax callback working, thanks to your explanation.

(It was even more cumbersome for me, since I needed to alter two filters based on the value of one filter, and since Views wraps the filter widgets in it's own classes, the #prefix and #suffix settings don't allow you to wrap two fields together nicely. I had to return my whole form in my Ajax callback, and manually reset the $form['#method'] to "get" to make it work.)

Still, I wish there was a way to do this in a more elegant way. Perhaps we could assign some form value which Views could look for, and if it was present, the Javascript you have above would populate the form values on Ajax submit. We don't necessarily need to pass a select value, though. We could just as easily pass those values as Drupal Javascript settings (which makes sense, since it deals with Ajax).

Only one problem remains after this. As I mentioned before, submited values can be found in $form_state['input'] for a normal views submit and in $form_state['values'] for an ajax call. One solution is:

After that the default values for widgets will always be found in $form_state['input'] even for ajax calls.

And another note:
If you want to position your extra widget(s) in the exposed filters form you need to also add info to the $form['#info'] array in the correct position.
For example, to add a "brand_selector" widget right before a filter called "model_selector":

Using Javascript settings is a nice solution, but my form now only behaves correctly on the first Ajax request. Since I am returning the entire form via Ajax, I'm guessing that the behavior needs to be re-attached or something after the first Ajax response. (I tried using the template file, but couldn't get it to work... not even after I flushed my caches... strange.)

Here's a solution which is working for me, using a Drupal "behavior". This can be done in a form_alter function... or, we can have Views sniff the form for any #ajax elements, and then add the Javascript if it finds some. Here's a proposed new version of views_form_views_exposed_form_alter().

<?php/** * Implement hook_form_alter for the exposed form. */function views_form_views_exposed_form_alter(&$form, &$form_state) {// Since the exposed form is a GET form, we don't want it to send a wide // variety of information.$form['form_build_id']['#access'] = FALSE;$form['form_token']['#access'] = FALSE;$form['form_id']['#access'] = FALSE;

Nice. I'm rather new to drupal, and still unsure how to use behaviors. Your solution is perfect.
The first 3 lines aren't needed though, since #access already is false, or at least it was for me. I had to change it to true in order to get them to render.
The foreach loop could even be integrated in views, I'd say. merlin's choice, I guess.

Question: views_form_views_exposed_form_alter is an implementation of hook_form_views_exposed_form_alter, right? If so, how do you know it's the last one to run? If i have mymodule_form_views_exposed_form_alter that creates a #ajax, then it has to come first, in order to actually have a #ajax that the foreach loop can find.
If indeed this is a issue, wouldn't this code work better in the template_preprocess_views_exposed_form function?

Hi there, I see the level of this conversation is higher than my knowledge, but i need to constructo a user (register and profile) form_alter including an ajax dependent dropdown and I have THE problem: ajax don´t work.
So, after reading this thread I more or less understood everything but I see you didn´t say anything final about the merging of $form_state['values'] and $form_state['input'] arrays... where do I have to place it?

Any help will be really welcome (It took me 3 days to finish the dropdowns :P)

Using the code in #8 allows my hook_alter AJAX code to "work" for an exposed view filter, and I'm trying to set my $form_state['values'] and $form_state['input'] to be the same, but submitting the form doesn't return any results, and I'm not sure how to check to be certain all my fields are being passed properly. I was thinking of setting them equal as part of the callback function, but those are only called for 2 of my 3 fields.
If I do a dpm($form) or dpm($form_state) as part of my callback I think I can see the inputs getting set, but I'm not sure where to set them for certain for the submit. I tried hooking into hook_submit to set them but didn't have any luck with that.
I hope I'm not rambling too much, I've very new to Drupal development, and feeling very frustrated.
I'm not even sure its the inputs holding me back at this point. Could anyone share some working code?

Follow-up to #8 and why solution mentioned in #7 working only first time - it's simple, after first request, select lose it's wrapper, so on second call, ajax don't have the wrapper where it should put the response.

So, it can be fixed by wrapping the element returned by callback in the same wrapper.

Guys, so what is the last working variant for this?
I used the code mentioned in #7, but it work only for one element. But I have 3 select fields, each depends on the others, so when I changed the 2nd - the 3rd doesn't change. Any ideas why?
Thanks in advance

P.S.: I took the code from #8 and put it in the end of my hook_form_alter and it works properly. (at the first time it didn't). Thanks a lot!

So, I moved all of the javascript logic to a separate file, and all of the PHP logic into an #after_build callback. What's left is the merger of $form_state['values'] and $form_state['input']. After_build is too late to merge, but views' form_alter is too late as well. We're doomed to merge (if we want to) in our own form alter hooks.

Of course, this needs documentation (but way less documentation than before).

I just renamed the file to exposed-form-ajax.js (replaced the underscores to dashes) and I replaced ajax_object with ajaxObject. In Javascript you should use camelCase. I think we have to check the callback because this was an issue in another module.

The callback issue is not easy to solve because you can set the name of the callback. On "Manage display" there is a callback "field_ui_display_overview_multistep_js" which we don't want to extend with the exposed form info.

The patch uses "ViewsExposedFormInfo" instead of "exposed_form_info" as Drupal.settings name.

Patch #41 works for me except when I use ajax along with the module Views Dependent Filter that hides exposed filters via Ajax too. Looks like there is a conflict somehow, I opened a separate issue not to mess with the readability of this one but if you guys could help me out on that one too that would be awesome.

Guys, why do you say that #47 should be committed? There is only a zip file with a file which extends views_handler_filter_in_operator class. That isn't a patch and I don't know how it is related to this issue here.

@barraponto i have updated views to the latest dev code and i am still getting this error.

To make it easier for other to test this issue i have created a sandbox with this handler.
git clone --branch views_form_alter_test jucallme@git.drupal.org:sandbox/jucallme/1978134.git addressfield

enable addressfield and create a view with an administrative area field filter. Selecting the country throws the error i have been speaking about. The code associated with that can be found in addressfield_views_handler_filter_administrative_area.inc

@yannickoo Read #43 there i point out what i am doing in the patch to addressfield.... in which i need to implement a dependant drop down to an views filter option form. I have attached what i am working on simply for your connivence to test this case where by this patch here is failing. Else follow the steps i pointed out in #43 and implement your own dependant drop down in a views options form and you will have the same experience.

@jucallme, sorry for taking so long to reply. I've looked more closely at your code attached at #47. Your problem isn't related to the exposed forms, but to the views handler's settings form. Please consider views_handler::options_form() and it's usage in the views_ui/includes/admin.inc. Views uses some own mechanism for ajax processing.

Anyway, I'm not sure that solution used for the exposed forms can help for handler options form. I may try to find any other way, but I think it should be a separate issue.

Im having some troubles with the patch in #46. For some reason the normal exposed filter, when used in a block, becomes a POST instead of a GET. If I comment out line 17 of the javascript file, jQuery.extend(Drupal.ajax[ajaxObject].options.data, Drupal.settings.ViewsExposedFormInfo[name]);, then it stays as a GET.

Hmm. Actually this is because Im replacing the whole form as I've got seven dropdowns that are interdependent upon each other. If I dont explicitly set the form method to GET it comes back to the ajax call as POST.

Hi guys, I'm tried to make two interdependent dropdowns. I'm using #7 and has encounter error in ajax.js in line 133 (Has anyone encountered this error). I tried to catch it and discovered, that element_settings.url become as array.

#46 works great, but if you have a dynamic form with new subform appearing after ajax call (like herarchical select form). The drupal.settings contain form_info for the initial form, not the updated form. Hence, the newly subform does note trigger the callback.

To resolve this issu, don't attach setting to the form in the #after_build callback, but use drupal_add_js().

Tested patch #73 on views 3.8 finally got it working. I'm not sure if this patch is just for the Reference Option Limit module or for other things as well, but I want to stress the importance of good documentation. It took me a week to figure out how to use this module, and mostly by reading and re-reading error issues. Without proper documentation a lot of time and energy is wasted, please document well! For this particular patch, it took me a while to realize how views AJAX exposed forms would work. Hitting apply worked, but I didn't realize you have to set EXPOSED FORM, Exposed form style: | Settings: check Autosubmit and Hide Submit button. That may be basic knowledge to some, but not everyone knows this. My problem was also with another bad jQuery add on with the site I was working on that transforms select boxes to div wrapped a href dropdowns, but that's another story, and i'd pull that code if I had the choice. So yes, the patch works, and please please document well. And be well.