Bug Tracker

Opened 10 years ago

Closed 9 years ago

Last modified 7 years ago

#5010 closed bug (invalid)

show() & hide() do not work on elements that have a hidden parent

Reported by: fahrvergnuugen Owned by:
Priority: low Milestone: 1.5
Component: effects Version: 1.4.3
Keywords: show hide slideup slidedown Cc:
Blocked by: Blocking:

Description

show() and hide() (and all other toggle effects) will ignore elements that have a parent that is not visible. This may seem like correct behavior but one could make the argument that if you wanted to target hidden or visible elements you should do so with the selector and not rely on the code within show()/hide().

The current implementation limits what can be done with show & hide. The following example scenario demonstrates the problem with the current implementation:

The scenario: A page of products with attributes and descriptions. A filter for showing & hiding products based on their attribute values. A preference checkbox for showing or hiding the descriptions.

The problem: 1) User filters the products, which hides several of them 2) User turns off descriptions (developer uses .hide() on the description containers) 3) User changes the filter so that previously hidden products are now visible

In this scenario, we will now have some products with hidden descriptions and some products with visible descriptions. This is because hide() ignored the description containers on the filtered products in step 2.

Change History (9)

comment:1 Changed 10 years ago by jeanmonod

This problem happends only when we use the animated show/hide. Using hide(100) or even hide(0) doesn't act like hide(). Here is a test case to illustrate the situation:

<span id="parent1">foo<span id="child1">bar</span></span><br/>
<span id="parent2">foo<span id="child2">bar</span></span>
<script type="text/javascript">
$(document).ready(function() {
  $("#parent1").hide();$("#child1").hide();$("#parent1").show();
  $("#parent2").hide();$("#child2").hide(0);$("#parent2").show();
});
</script>

Result of this generate this text:

foo
foobar

comment:2 Changed 10 years ago by jeanmonod

For people who need a fix for this bug, here is a little hack to fix it:

  (function(){
    var originalHideMethod = jQuery.fn.hide;
    jQuery.fn.hide = function(speed,callback){
      // We have to fix the case when speed is define
      if ( speed !== undefined ) {
        // Foreach object, we must act different if they are visible or not
        $(this).each(function(){
          if ($(this).is(":visible"))
            originalHideMethod.apply($(this), [speed,callback]);
          else
            originalHideMethod.apply($(this),[null,callback]);
        });
      }
      originalHideMethod.apply($(this),arguments);
    };
  })();

comment:3 Changed 10 years ago by jeanmonod

Here is a better version of the fix, previous version was missing the return before parent call, and so was not usable in a chain call like $('foo').hide().show()

  (function(){
    var originalHideMethod = jQuery.fn.hide;
    jQuery.fn.hide = function(speed,callback){
      // We have to fix the case when speed is define
      if ( speed !== undefined ) {
        // Foreach object, we must act different if they are visible or not
        $(this).each(function(){
          if ($(this).is(":visible"))
            return originalHideMethod.apply($(this), [speed,callback]);
          else
            return originalHideMethod.apply($(this),[null,callback]);
        });
      }
      return originalHideMethod.apply($(this),arguments);
    };
  })();

comment:4 Changed 9 years ago by addyosmani

Type: bugenhancement

The current behavior that indeed is correct. If a user wishes to adjust what happens when the default behavior is applied, they can simply alter the parent elements to not be hidden, change the structure of their mark-up to better suit the problem being targeted or alternatively, use one of the suggested custom-fixes in the above thread. Moving this to enhancements.

comment:5 Changed 9 years ago by addyosmani

Milestone: 1.4
Version: 1.3.21.4.3

comment:6 Changed 9 years ago by SlexAxton

Milestone: 1.5
Priority: majorlow
Resolution: invalid
Status: newclosed
Type: enhancementbug

I went through this and figured out exactly which combinations work which way, and I think the way the library works makes sense.

http://jsfiddle.net/wWaqL/

There is one ambiguity with 'toggle' and whether it should be element specific or not, but unfortunately it's infeasible from a performance aspect to check all parents of every element that's hidden, so this interpretation of how it works automatically wins.

I agree it's confusing, but I think you may be happier with an application architecture that doesn't rely on this type of thing. If you need more convincing, we're all around in the #jquery channel on freenode. I know this is a bit of a weird one...

comment:7 Changed 9 years ago by michaelhaszprunar@…

Hi, I guess the greatest confusion for people is that they think, hide() is taking longer (e.g. using "normal" as default speed) than hide(0). I thought so myself until I looked at the jQuery core code. Maybe this has changed in the past?

But I have to agree and disagree Alex Sexton: I agree that toggle() and show() are a problem, when parents are hidden but children are not. But in my opinion, hide() can not be compared to toggle()/show() as hiding does not involve the parents visibility. So at least fix this for hide ;)

comment:8 Changed 8 years ago by masimao@…

I've resolved the problem with a dirty hack, i called a callback that do the same thing.

$("#element").hide("slow", function() { 

    $("#box-produto-visivel-zerar-estoque").show();

});

comment:9 Changed 7 years ago by calingasan

This issue only occurs on IE7.

Fix

$("selector").hide(0, function(){ $(this).hide(); });
Last edited 7 years ago by calingasan (previous) (diff)
Note: See TracTickets for help on using tickets.