4

I've got the following piece of Jquery:

$("#collapse-menu > li > a").click(function() {
    $(this).toggleClass("expanded").toggleClass("collapsed").find("+ ul").slideToggle("medium");
});

What it basically does is expands or collapses a menu of nested "lists" which contain dropdowns (simplified example):

<ul id="collapse-menu">
   <li><a class="expanded">Basic Details</a>
      <ul>
         <li>
            <select> .... </select>
         </li>
         <li>
            <select> .... </select>
         </li>

The code works absolutely fine EXCEPT when a large value is selected in any of the dropdowns. At that point, when clicked, the menu will still expand/collapse correctly but "flash" quickly while doing so, as if the entire element was being reset somehow. The data itself is fine but it's the flashing that's unwanted.

The strange thing is that if a small value is selected in a dropdown, there's no flashing. When a large value is selected (say, above 30 in an age dropdown of 18-99), the flashing starts happening.

Can anyone tell me why this is happening? Or whether there's something not right about the Jquery that's causing this.

Thanks.

UPDATE:

Adding a bounty to this. Have tried a few similar plugins/solutions out there on the net but they all seem to suffer from this "flashing" problem when large dropdown values are selected by default.

If it helps, here's a typical similar solution: http://www.i-marco.nl/weblog/jquery-accordion-menu/index_collapsed.html# ... but it suffers from the same problem when dropdowns are added inside the accordion.

I hope someone has a clean solution, instead of needing to hack this somehow.

Tom
  • 30,090
  • 27
  • 90
  • 124
  • Out of curiosity, why use such large drop-downs? There are other (better) ways to enforce entry of 2 digits, minimum value of 18, etc. This would make your presented problem go away, and would make your application easier to use (IMHO anyway) to boot. My general rule of thumb is that a drop-down shouldn't contain more than about 10 items, and absolutely no more than 20. – GalacticCowboy Mar 26 '10 at 21:42
  • @GalacticCowboy: Thanks, but in this case long dropdowns are needed. It's the overall simplest way for presenting the needed form elements. For example, it includes a country dropdown (220 options). – Tom Mar 26 '10 at 21:44
  • I'd argue that select list (drop downs) are fine up to 100 elements, as long as they are sorted logically so that a user can quickly navigate them. select lists with 200+ options are when you realize that the usability is all but gone. – scunliffe Mar 26 '10 at 21:56
  • Each case is different. Anyway, the question is not about usability. There is no better way to list countries than in a select and it exceeds 200 options. – Tom Mar 26 '10 at 22:04
  • 2
    Not a real answer but did you ever consider at least providing the user a autocomplete instead of a normal dropdown http://bassistance.de/jquery-plugins/jquery-plugin-autocomplete/ – jitter Mar 27 '10 at 00:33
  • @jitter: thanks but it has nothing to do with my question. I have dropdowns for a reason. – Tom Mar 27 '10 at 00:54
  • Can't reproduce your problem. Check here http://jsbin.com/ixake . Probably has to do with your styling maybe add some css – jitter Mar 27 '10 at 07:40
  • @jitter: thanks very much for trying this out. Actually the problem is present in your version too! If you select large values, and then click repeatedly and fast, it starts flashing... but only when large values are selected! You can see flashing even better if you add a background color. I checked my CSS, it's not that. It's something in Jquery "queuing" events in a way that chokes itself. I'm going to play with adding delay between the collapse/expand events. – Tom Mar 27 '10 at 14:51
  • Can you provide info on what OS/browser combos you see this on because when I answered, I don't think I was seeing the same problem as you (I occasionally saw a slight hesitation when sliding up/down as the browser tried to re-render the large selects). I actually don't see any problem (as others have noted in comments) on the page posted by jitter (Firefox 3.0.18 on Ubuntu 8.04). – Rob Van Dam Apr 15 '10 at 19:13

4 Answers4

3

From my observation: The issue seems Operating System dependent. The selects are painted by system, as they're system controls. On my Linux machine I experience no problems with blinking animation in the http://jsbin.com/ixake example. I expect You tested it on Windows (r)

It looks like the select is "scrolled" to the proper value everytime it's repainted. And that happens a lot while animating.

The easiest solution would be to substitute system selects with html-based selects to remove system dependency. There are unobtrusive jquery plugins that will do it for You.

Try this or pick any from here if that first one wasn't too good.

After that Your animation should depend only on JS and styling.

Community
  • 1
  • 1
naugtur
  • 16,827
  • 5
  • 70
  • 113
  • Thanks, using some plugin is an option but would produce a lot of hassle for such a simple problem. I have approx 20 dropdowns nested (just has to be), all of which take context-specific values via the PHP form class that generates them, some that load dynamic content via ajax based on other dropdown selections, the form is postable, etc. It becomes too much to start incorporating a plugin when the problem is just an aesthetic annoyance. – Tom Apr 15 '10 at 00:16
  • 1
    You're not right. You just have to call $('select').whateverThePluginIsCalled() and it's all done. It's jquery. There is no incorporating anything. Just add the script tag and run the function in the ready event. And no difference is visible from the server – naugtur Apr 15 '10 at 07:55
  • And You will never get rid of that effect if You keep using system controls. – naugtur Apr 15 '10 at 07:56
  • Hmmm... on second look, the basic combobox does look quite simple. Will give it a try before the deadline and report back. – Tom Apr 15 '10 at 13:16
  • A working hack (if any exist) for this problem will surely be much more complicated than that. Good luck meeting the deadline. – naugtur Apr 15 '10 at 16:01
  • Ok, after playing around with this, I can solve the problem with this solution & CurtainDog's solution/hack. The problem is indeed in the reapplication of the select value when it's redrawn. As I can't divide the points 50/50, I'll accept this one as it's a more sustainable solution. @naugtur: Thanks for all the time spent on this. – Tom Apr 17 '10 at 13:18
2

I think the problem is that every time the element is resized the dropdown scrolls to the selected element, which causes the flashing.

The answer would be to save each selection in javascript (on change say), then when the animation starts to deselect the value and then restore it when the animation stops. This will give you the same performance as you get when you have a small value selected, while preserving the user's selection.

You might also want to ensure that the form cannot be submitted while it is in a transitional stage, otherwise you'll get bad values coming back.

CurtainDog
  • 3,175
  • 21
  • 17
  • Thanks - I suspect you're right. If no better answers crop up, will test this before the deadline and report back. Theoretically, sounds like the best solution so far. – Tom Apr 15 '10 at 00:11
  • This should work, but it will require a lot of mess in the aplication and cause complications with every change in number of selects in the future development. (especially compared to a one-liner calling a jquery plugin) – naugtur Apr 15 '10 at 16:01
1

I personally think autocomplete may really be the way to go. However, I had the idea that hiding the long select by substituting a fake short one would make the slide smoother. Seems to work better on the one browser I tested (Firefox 3.0.18). The code could probably be cleaned up and there is the bug that sometimes the selects won't match sizes by default due to the internal scrollbars but that shouldn't be too difficult to fake.

$("#collapse-menu > li > a").click(function() {
    var was_expanded = $(this).hasClass('expanded');
    var uls = $(this).toggleClass("expanded").toggleClass("collapsed").find('+ ul');
    if (was_expanded) {
        $(this).parent().find('select').each(function() {
            var fake = $('<select class="fake"><option>' + $(this).val() + '</option></select>');
            $(this).parent().append(fake);
            $(this).hide();
        })
        uls.slideUp('medium', function() { });
    } else {
        $('.fake').remove();
        $('select').show();
        uls.slideDown('medium', function() { });
     }
});
Rob Van Dam
  • 7,812
  • 3
  • 31
  • 34
  • Thanks but this solution fails. Unfortunately worse flashing than not adding anything at all. Autocomplete is not a suitable option in this case as I have several selects inside the accordion. – Tom Apr 15 '10 at 00:07
1

What you can do is disable the select lists before animating the ul.

        $("#collapse-menu > li > a").click(function() {
            $(this)
                .toggleClass("expanded").toggleClass("collapsed")
                .find("+ ul").find("select").attr("disabled","disabled").end()
                .slideToggle("medium",function(){
                    $(this).find("select").each(function(){this.disabled=false;});
                });
        });

give that a try and report back.

You will probably want to style (CSS) the disabled select lists to look identical to non-disabled ones.


NOTES

The above has a side effect of not submitting the selected values when a form is submitted. If this is a problem for you then I suggest you either remove all options from the select list except for the selected option before animating and then add them all back in once animation is complete. And if that won't work for you naugtur's suggestion to use HTML-styled select lists is probably the best option.

p.s. don't bother trying to use the readonly attribute on the select list...it doesn't exist.

David Murdoch
  • 87,823
  • 39
  • 148
  • 191
  • Thanks but this solution fails. Flashing persists and now with the added "delay" of waiting for the disabled to clear. If only small values in the selects are selected, flashing disappears, suggesting this solution does not have the desired effect. – Tom Apr 15 '10 at 00:09
  • Hm, It did for me. I have no idea what you mean by "waiting for the disabled to clear" – David Murdoch Apr 15 '10 at 15:03
  • I'm thinking you should go with naugtur's suggestion of HTML select lists. – David Murdoch Apr 15 '10 at 15:05