mat_boy
mat_boy

Reputation: 13666

JQuery objects reference after element replacement

When writing some Javascript, I usually define upfront all the elements I need, e.g.

var $body, $header, $footer, $anInput;

$(document).ready(function () {
  $body = $('body');
  $header = $('div#header');
  $footer = $('div#footer');
  $anInput = $('form#myForm input');
};

Now, If I do something like

$body.html($body.html());

(I know, does not make sense, but it could be for instance obtained via an AJAX call).

Am I still entitled in using $header, $footer, $anInput or should I get the reference once again?

Actually, my Javascript code still works, so I would answer yes, but I suspect that I'm missing something.

Upvotes: 0

Views: 38

Answers (3)

Peter Behr
Peter Behr

Reputation: 607

You can check this yourself: the references still point to objects which can manipulate them however you want, but the objects they refer to are no longer in the DOM, so they don't affect anything you can see in the browser. And any event listeners that were attached to any elements in the body were also removed, so you'd have to attach new ones. Your options:

  • Get new references to the implicitly inserted DOM elements (or in your case jQuery wrappers around them) each time. This becomes really difficult to maintain as complexity grows and components change.
  • Keep component updates more atomic, so that you never replace whole DOM elements, only modify text or attribute values. Good rule of thumb.
  • Or always render the whole page again (attaching listeners etc.) from an authoritative state. Which might mean not using frameworkless jQuery anymore.

Upvotes: 0

ibrahim mahrir
ibrahim mahrir

Reputation: 31692

That because when using jQuery.html or Node.innerHTML the entire content of the element is removed and replaced by new content. And since elements (nodes) are objects, and objects in javascript are passed by reference not by value, the old references will point to object that have been removed, thus the references will be useless and error-prone if used.

You can store selectors instead of jQuery objects and use $(...) like this:

header = 'div#header';
footer = 'div#footer';
anInput = 'form#myForm input';

$(header)....;
$(anInput)....;
// ...

Or update the objects every time you change the HTML which is better because then you'll call $(...) less times which is a bonus in performance.

Upvotes: 1

Neil
Neil

Reputation: 14313

Your jQuery reference will be wiped. So, if you decide to do $body.html($body.html()), your selectors will all break.

$(document).ready(function () {
  $body = $('body');
  $header = $('div#header');
  $footer = $('div#footer');
  
  $footer.html("test 1");
  
  $anInput = $('form#myForm input');
  
  $body.html($body.html());
  
  $footer.html("attempted to change value");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<body>
	<div id="header"></div>
	<div id="footer"></div>
</body>

Notice how footer is still test 1.

You just need to re-initialize the selectors.

$header = $("div#header");

Upvotes: 1

Related Questions