Warning: Wear your peril sensitive code goggles before viewing this post. My code is probably inappropriate for young audiences, the elderly, people with heart conditions, or overly sensitive coders who know the right way to do it.
A little back-story here. I have been a themer for most of my time in the Drupal world. Now, that is changing, as I am moving more, simultaneously, into coding and project managment, however, what this means is that I really probably don't know the right way to do what I have done, so I relied on the time tested method of hacking the hell out of something like it was attacking my family.
The problem
I have setup a nice View on my Drupal 6 install that exposes a bunch of filters, and allows the user to "search" on a range of criteria. I needed to set those filters off on the left side of the page, and collapse them all down, so all you saw was the label and a little arrow, unless there was data from a previous "search." I also needed a form reset, one that was particular to this sort of filter set.
Normally on a page view, exposed filters show up above the results, are not hidden, and there is no reset button. That wasn't going to do for my customer. So I tried a number of things, and ended up with one that works, for the most part. Here they are:
Views Filterblock
The Drupal 5 version of View Filterblock accomplished some of the things I was looking for, namely the putting of the filters in a block, and putting them where I wanted them. What it didn't do was work with Drupal 6. Aha, I can port a module to Drupal 6 says I!
Um, yes, and I did, to a small degree. However at that time, I was chatting occasionally with merlinofchaos about the best ways to do this, and implementing his ideas in my patch for a Drupal 6 version of Views Filterblock. I guess that he was so distraught with the warts and scabs in my code that he threw his hands up and created all of the functionality from Views Filterblock natively in Views2. Thanks Earl!
Views2 Exposed Filters in Block
This led me to try the new code that merlinofchaos had conjured, and yes, it does work beautifully, if your site isn't this one, and if your block isn't on the same page as the displayed results. For some reason, on my project, if the block of exposed filters is located on the same page as the results, the .form-text text fields don't expose. So, pretty much it's just broken.
I need to file a bug for this, but I haven't gotten around to it, because I had been working on another way:
Hack it like it's a zombie and you are Shaun of the Dead!
My current solution, and probably not the final one, was to use CSS, jQuery, and just bully things around on the front end until they looked right. Now, I have approval from the customer to make things happen with jQuery, so this is fine by me, however I did want things to fail at least gracefully, so I made sure to leave the current basic functionality of Views2 exposed filters in place.
So for the solution to having each exposed filter be the expandable/collapsible type, and to hide all of them, and expose only the vocabulary terms, I did the following in jQuery:
// Hide our exposed filters form and make labels that are clickable
$(".views-exposed-widget label").addClass("expand-label");
$(".views-exposed-widget label").siblings('div').hide();
$(".views-exposed-widget label").click(function (e) {
var $hides = $(e.target).siblings('div');
$hides.toggle();
e.preventDefault();
return false;
});
// This allows the vocabulary terms to always be visible
$(".views-exposed-widget label:first").siblings('div').show();
$(".views-exposed-widget:last").addClass("buttonForm");This is graceful enough, in that it won't hide anything if this code can't run, such as in a scenario where JavaScript is turned off. I of course styled these labels in CSS, and applied a little down arrow as a background image to make it purty.
Next, I needed to be able to reset the form to a clear, usable state, one where all items for this view were visible. This was made necessary because the complexity of the form, and the fact that it likes to remember the last value added to it, a nice feature to be sure, but one that we would like to be able to clear at a click of a button.
A simple .reset() didn't work, and not being sure what the right way to do it was, and apparently nobody else knew what the right way was, I just went ahead and hacked some more!
// Add a reset button to our forms
$(".views-exposed-widget #edit-submit").after('<input type="button" onclick="formReset()" value="Reset form">');So far so good, that puts the button there, but probably it should do something when we click on it.
function formReset(){
// Clear all of the text inputs
$(".views-exposed-widget input.form-text").each(function(n,element) {
$(element).val('');
});
// The first select is a taxonomy selector, let's select them all
$(".views-exposed-widget:first .views-widget select option").each(function(n,element) {
$(element).attr('selected', 'selected');
});
// Set any of the exposed filter options back to the first option
$(".views-exposed-widget select option:first-child").attr('selected', 'selected');
// Submit the cleared form to reset the page to all items visible
$("form#views-exposed-form-range-search-page-1").submit();
};Ah, that does it for resetting the form. The last thing the customer wanted, to make it more intuitive for people who are searching on several criteria, is that when they are narrowing the search, they should be able to see the items that they have entered, and by default above, we have hidden all of the options, so they would have to click to expose any that have a value. Not good enough, so a bit more hackery to fix that.
// This checks to see if there is a value in a field, and if so, shows those fields
$(".views-exposed-widget input.form-text").each( function(n,element){
if ($(element).val()!='') {
$(element).parents().show();
$(element).parents().siblings(".views-operator").show();
return true;
}
});Lastly, I still needed to put all of this business over to the left side. This is by far the most limiting part of my hack, as it requires that the left side-bar be empty, and thus not actually be there, because I fake a left sidebar. In my style.css I hacked the following:
.page-elastomers .views-exposed-form {
background:#F1F1F1 none repeat scroll 0 0;
border: 1px solid #CCCCCC;
float:left;
margin-right:-190px;
position:relative;
width:149px;
font-size:0.9em;
padding:25px 20px 10px;
z-index:2;
margin-left: -20px;
border-left: 0px;
}
.page-elastomers .view-content {
float: left;
margin-left: 200px;
}A better way
I am hoping in the future, perhaps after I get off my duff and submit a bug report, and then try to figure out if I can help on fixing it, I can cut out the CSS hack on the end, and expose those filters as a true block. That would make this much more flexible.
Of course I can use most of my current hackery without much modification even if I am using his block, so this is good. I am listening for suggestions on the "Drupal Way" or even just a better way, to implement what I have done so far. I am sure there is a hook_form_alter or a hook_theme or something that I could do, but I haven't been able to figure out how that works yet. Also, merlinofchaos has been crazy with the updates on Views2, so I might just wait until that settles down a bit.
Suggestions Welcome!


update
Hey,
great article! I did some optimisations that you might like. Its also JSLint compatible. Take a look:
// Hide our exposed filters form and make labels that are lickable
var filter_expand = function(n) {
$(n.target)
.toggleClass("filter_label_collaped")
.siblings("div").toggle();
}
$(".views-exposed-widget label")
.addClass("filter_label_collaped")
.click(filter_expand)
.siblings("div").hide();
// This checks to see if there is a value in a field, and if so, shows those fields
$(".views-exposed-widget input.form-text").each(function(n, element){
if ($(element).val() !== "") {
$(element).parents().show().siblings(".views-operator").show();
$(element).parents().siblings("label").removeClass("filter_label_collaped");
}
});
best regards,
massa
Awesome, but...
Thanks for the input, but did you really mean to change my comment from saying "clickable" to "lickable"? ;)
It will be interesting to watch my Google Analytics to see who I get from that one word alone.
sightly modified
Hey thanks for this snippet, I too could not get any of the form_alter functions to work as a filter reset, but luckily found your solution, I have made some minor changes and posted a revised snippet to a related thread on drupal.org
IE Problem?
I modified this a bit and it works well in Chrome and Firefox, but in IE the background image doesn't show up. I've set it in CSS and used .addClass to attach the class to the appropriate elements. Weirdly, when you click on the label twice to show/hide the element, the image reappears. Any idea what's up?