JasonDavis
JasonDavis

Reputation: 48963

jQuery Cached Selector does not work correctly

Using JavaScript and jQuery I am trying to cache a Selector to an Objects property.

I save $("#dnsTitle") to zPanelDNS.cache.dnsTitleId

however down in my zPanelDNS.events function you can see where I try using the Selector and the Cached version.

For some reason the cached version does not work as I thought it would. I write both selectors to console log and they both find the target element but for some reason the cached version does not work.

Here is the output in console of the 2, you can see they are slightly different...

$("#dnsTitle") WORKS =

[div#dnsTitle.account accountTitle, context: document, selector: "#dnsTitle", jquery: "1.9.1", constructor: function, init: function…]

zPanelDNS.cache.dnsTitleId DOES NOT WORK =

[context: document, selector: "#dnsTitle", jquery: "1.9.1", constructor: function, init: function…]

The JavaScript...

var panelDNS = {

  unsavedChanges: false,

  init: function () {
    panelDNS.events();
  },


  cache: {
    dnsTitleId: $("#dnsTitle"),
    translation: {
      absolute: 0,
      relative: 0,
      sinceDirectionChange: 0,
      percentage: 0
    }
  },

  events: function() {

    // Activate SAVE and UNDO Buttons when Record Row EDITED
    $(document).on("keydown", "#dnsRecords input" ,function() {

        // Using Selector
        // DOES WORK
        $("#dnsTitle").find(".save, .undo").removeClass("disabled");
        console.log($("#dnsTitle"));

        // Using Cached Selector panelDNS.cache.dnsTitleId
        // DOES NOT WORK
        //panelDNS.cache.dnsTitleId.find(".save, .undo").removeClass("disabled");
        console.log(panelDNS.cache.dnsTitleId);

    });

  }

}

$(function(){
    panelDNS.init();
});

Upvotes: 0

Views: 846

Answers (1)

T.J. Crowder
T.J. Crowder

Reputation: 1074595

$("#dnsTitle") looks up the element with that ID immediately when you call it, and returns a jQuery object wrapping the element (if found) or an empty one (if not). It doesn't re-query or something when you try to use it later. Apparently, the element with that ID doesn't exist when the code creating the panelDNS object is created, but does exist later when a key is pressed.

There could be any number of reasons for that. For instance, if the script element for your code is higher up in your HTML document than the dnsTitle element, that would be why; the element doesn't exist until that part of the document is parsed.

For example, this will not turn the text of the myElement element blue:

<script>
$("#myElement").css("color", "blue");
</script>
<!-- ... -->
<div id="myElement">This text will not turn blue</div>

but this will:

<div id="myElement">This text WILL turn blue</div>
<!-- ... -->
<script>
$("#myElement").css("color", "blue");
</script>

This is one of many reasons that, unless you have a good reason not to, you should put your script elements at the bottom of your document, just before your closing </body> tag. That's the recommendation from the YUI Best Practices and the Google Closure Library teams.


There were a couple of other problems with that code, not least that it had a syntax error where you were defining events, and you were using PanelDNS and panelDNS interchangeably, but JavaScript is case-sensitive and so they're not the same thing.

Here's that code with the changes described above and fixes for the other problems I noticed, see inline comments with ****:

var panelDNS = {

  unsavedChanges: false,

  init: function () {
    // **** Removed unnecessary second `ready` call

    // **** Get the element here
    panelDNS.cache.dnsTitleId = $("#dnsTitle");

    // **** Call the `events` function to hook events
    panelDNS.events();

    // (Instead of `panelDNS` above, you could use `this`, but since you
    // only have one `panelDNS` object, it's simpler to use that)
  },


  cache: {
    // **** Removed dnsTitleId here
    translation: {
      absolute: 0,
      relative: 0,
      sinceDirectionChange: 0,
      percentage: 0
    }
  },

  events: function() { // **** Made this a function

    // Activate SAVE and UNDO Buttons when Record Row EDITED
    $(document).on("keydown", "#dnsRecords input" ,function() {

        panelDNS.cache.dnsTitleId.find(".save, .undo").removeClass("disabled");
    });

  }

}

$(function(){
    panelDNS.init();
});

Upvotes: 2

Related Questions