3

For some reason my call to nested jQuery.each() functions are losing scope for some variables, but not others. In the code below, the Client.KNE reference works, but ClientDiv does not, even though prior to that each, both are defined, populated variables...

By switching Client and ClientDiv to global variables, it works, but I feel like I should not have to create global variables here...

Doesn't Work:

jQuery.each(Messages.Additions, function (clientIndex) {
    var Client = Messages.Additions[clientIndex];
    var ClientDiv = $("#clientTitle_" + Client.ClientID);

    if (ClientDiv.length == 0) {
        $("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
    } else {
        jQuery.each(Client.KNE, function (kneIndex) {
            var KNE = Client.KNE[kneIndex];                       // Works
            var KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE);  // DOES NOT WORK

Does Work:

jQuery.each(Messages.Additions, function (clientIndex) {
    Client = Messages.Additions[clientIndex];
    ClientDiv = $("#clientTitle_" + Client.ClientID);

    if (ClientDiv.length == 0) {
        $("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
    } else {
        jQuery.each(Client.KNE, function (kneIndex) {
            KNE = Client.KNE[kneIndex];                       // Works
            KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE);  // Works

Anyone know what I'm doing wrong in the first version? Or is this a bug? Why does the one variable work but the other doesn't...

From here: Jquery $().each method obscures 'this' keyword it looks like I could pass the variables into the function call, but should I have to?

Tried the above link, and it is not working:

jQuery.each(Messages.Additions, function (clientIndex) {
    var Client = Messages.Additions[clientIndex];
    var ClientDiv = $("#clientTitle_" + Client.ClientID);

    if (ClientDiv.length == 0) {
        $("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
    } else {
        jQuery.each(Client.KNE, function (kneIndex, Client, ClientDiv) {
            var KNE = Client.KNE[kneIndex];
            var KNEDiv = ClientDiv.find("#kneTitle_" + KNE.KNE);   //Does not work - ClientDiv undefined

Similar questions without satisfactory answer: Scope of jQuery each() function?

SOLUTION

$.each(Messages.Additions, function () {
    var $Client = this;
    var $ClientDiv = $("#clientTitle_" + $Client.ClientID);

    if (!$ClientDiv.length) {
        $("#ClientTemplate").tmpl($Client).appendTo("#ClientContainer");
    } else {
        $.each($Client.KNE, function () {
            var $KNE = this;
            var $KNEDiv = $ClientDiv.find("#kneTitle_" + jq($KNE.KNE));    
            // SWITCHED TO $ PREFIX
Community
  • 1
  • 1
Tom Halladay
  • 5,651
  • 6
  • 46
  • 65
  • 1
    Shouldn't that be ".find()" with a lowercase f? – Blazemonger Aug 30 '11 at 17:37
  • Good catch, I actually fixed my code here right after I posted it. Unfortunately that's not the cause of my problem though ;-) – Tom Halladay Aug 30 '11 at 17:46
  • Please read the "**When asking a JavaScript question, you should**" part [here](http://stackoverflow.com/tags/javascript/info) – thorn0 Aug 30 '11 at 18:15
  • I meant just this item: "Isolate the problematic code and reproduce it in an online environment such as jsFiddle or JS Bin". No, your snippet is not clear enough, because it's not isolated. – thorn0 Aug 30 '11 at 18:39

1 Answers1

3

You can try this using this keyword which points to the current item in the loop. Instead of checking for if (ClientDiv == null) you should check for if (ClientDiv.length > 0) because jQuery returns am empty object if it do not finds the element so that check will fail.

var additions;
jQuery.each(Messages.Additions, function () {
    var $clientDiv = $("#clientTitle_" + this.ClientID);

    if ($clientDiv.length == 0) {
        $("#ClientTemplate").tmpl(Client).appendTo("#ClientContainer");
    } else {
        jQuery.each(Client.KNE, function () {
            $clientDiv.find("#kneTitle_" + this.KNE);
        });
    }
});
ShankarSangoli
  • 69,612
  • 13
  • 93
  • 124
  • Thanks for the pointer on the null check. However, I don't see how your code helps me avoid a re-selector for ClientDiv in the child each loop. The reference to Client is the part that works, it's ClientDiv that is failing, and presumably I would have to re-select using the Additions/Client reference? – Tom Halladay Aug 30 '11 at 17:45
  • That did work Shankar. What does adding the $ before the variable do? Is that just making it a global variable? – Tom Halladay Aug 30 '11 at 17:56
  • The length check looks backwards--shouldn't it be !clientDiv.length? – jmans Aug 30 '11 at 17:59
  • @Jmans, you're saying !clientDiv.length will evaluate to false when length is 0? That's a new one on me, but I like it if that's the case. – Tom Halladay Aug 30 '11 at 18:22
  • @Tom - `!clientDiv.length` will return `true` if `length == 0`. – ShankarSangoli Aug 30 '11 at 18:24
  • 1
    @Shankar, I'm still curious, what effect does prefixing with $ have on the variable? Is that simply shorthand for global, or is there some jquery magic happening there? – Tom Halladay Aug 30 '11 at 18:24
  • @Tom - There is no difference it will simply help ourself clear that its a jQuery variable in the code. – ShankarSangoli Aug 30 '11 at 18:25
  • @Tom it's a little shortcut. if (clientDiv.length) evaluates false if clientDiv is empty, null, false, undefined, NaN... – jmans Aug 30 '11 at 18:35