Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does jQuery fail to hide certain HTML?

I've been running my head into a wall trying to figure this out. Take the following HTML body:

<body>
<div id="project">
  <h1>Hi</h1>
  <h2>Hello</h2>
</div>
</body>

And the following jQuery code:

$(function(){
  var h = $('#project').html();
  $('#project').remove();
  $(h).hide().appendTo('body');
  alert("Created HTML, hide, and appended!");
});

The $(h).hide() portion causes jQuery to throw an exception in Safari 4 and Firefox 3.5.

Safari: TypeError: Result of expression 'this[a].style' [undefined] is not an object.
Firefox: uncaught exception: [Exception... "Could not convert JavaScript argument arg 0" nsresult: ...]

When I change the HTML to contain just one of the two headings (if you remove the <h1> or <h2> from the HTML, the script runs successfully. Why is this?

To try for yourself, see http://jsbin.com/avisi/edit

Edit: I'm not actually trying to remove and element from the DOM and re-insert it by copying the HTML. This is just a test case for an error I'm having in more complex code, and I'm trying to understand why this error occurs. I agree that, if I wanted to accomplish just what is shown here, I would use something like $('#project').remove().children().appendTo('body')

like image 573
Ryan Avatar asked Feb 19 '10 09:02

Ryan


People also ask

Can we use a jQuery method to hide an HTML element?

By using show( ) and hide( ) methods you can show and hide HTML elements in jQuery.

Which jQuery method is used to hide the selected item?

The hide() is an inbuilt method in jQuery used to hide the selected element. Syntax: $(selector).

What is the meaning of this jQuery code $( P Hide () do?

The jQuery hide() method is used to hide the selected elements. Syntax: $(selector). hide();

What is difference between remove and hide in jQuery?

hide() sets the matched elements' CSS display property to none . remove() removes the matched elements from the DOM completely. detach() is like remove() , but keeps the stored data and events associated with the matched elements.


2 Answers

I cannot duplicate your error in Firefox. However, you might want to try cleaning it up with the following:

$('#project').remove().children().appendTo('body').hide();

Broken down, this is what's happening

// Get the `project` container
$('#project')
    // Remove it from the page
    .remove()
    // Get its children (the h1, h2, etc)
    .children()
    // Append those nodes to the body
    .appendTo('body')
    // Hide those nodes
    .hide();

Others are proposing that .hide() is causing problems since the node that it is being applied to is not part of the main document; however, this is just not the case. As long as you maintain a reference to any node, you can affect its style property (via hide, show, etc).

One things you might want to check is to make sure that $('#project') is actually returning the (if any) expected node. Problems may arise otherwise.


So I poked around in Safari and found your problem. Here's a dump from the developer console.

> var h = $('#project').html();
undefined
> var t = $(h);
undefined

So far, so good. undefined here simply means that the statement (the var statement) has no return value (which it doesn't)

> t.hide()
ajax.googleapis.com/ajax/libs/jquery/1.4.0/jquery.min.js:131TypeError: Result of expression 'this[a].style' [undefined] is not an object.

Here's the error that you described. Inspecting each item in jQuery object will reveal the error below

> t[0]
<h1 style=​"display:​ none;​ ">​Hi​</h1>

Good...

> t[1]
(whitespace)

Dammit. Really? Here's the problem. whitespace nodes have no style attribute, which is what's causing the problem.

> t[2]
<h2>​Hello​</h2>

This is why copying the HTML of one node to another just to move those nodes is a bad technique. I suggest you use the snippet that I provided above.

like image 123
Justin Johnson Avatar answered Oct 05 '22 01:10

Justin Johnson


There's a text node being selected in the $(h). We can filter that out using the filter function though.

This should work (I've only tested in FF though):

$(function(){
  var h = $('#project').html();  
  $('#project').remove();
  $(h).filter("*").hide().appendTo('body');

 alert("Created HTML, hide, and appended!");
});

Pretty wierd behaviour IMO.

like image 45
Mark Worth Avatar answered Oct 05 '22 01:10

Mark Worth