0

I faced a very interesting issue today which many of you might find elementary but since I am just learning to use jQuery, I am interested to know how this works.

I have two arrays and I'm iterating through the elements of array. One array is arrAllDetailsConstantData and the other one is arrAllDetails. I want to compare using arrAllDetailsConstantData and update using arrAllDetails.

I am using nested loops. But what is happening is that while updating array arrAllDetails, array arrAllDetailsConstantData is also getting updated. I assume this is somehow related to scope of parent this (though I am just guessing). Can you please help me with this?

Here is my code:

$.each(privateVariables.arrAllDetailsConstantData, function() {
    if (this.AssociationId == value && this.uniqueChargeAttr == uniqueChargeAttr) {

        if (this.Units == $("#txtUnits").val() &&
            this.Modifier1 == $("#txtModifier1").val() &&
            this.Modifier2 == $("#txtModifier2").val() &&
            this.Modifier3 == $("#txtModifier3").val() &&
            this.Modifier4 == $("#txtModifier4").val() &&
            this.DxOption == $("#ddlDxOption").val() &&
            this.DxCode1 == $("#txtDx1").val() &&
            this.DxCode2 == $("#txtDx2").val() &&
            this.DxCode3 == $("#txtDx3").val() &&
            this.DxCode4 == $("#txtDx4").val()) {

        } else {
            $.each(arrAllDetails, function() {
                if (this.AssociationId == value && this.uniqueChargeAttr == uniqueChargeAttr) {
                    this.ActionType = "M";
                    this.CptName = $("#lblCptDesc").text();
                    this.CptDesc = $("#lblCptDesc").text();
                    this.Units = $("#txtUnits").val();
                    this.Modifier1 = $("#txtModifier1").val();
                    this.Modifier2 = $("#txtModifier2").val();
                    this.Modifier3 = $("#txtModifier3").val();
                    this.Modifier4 = $("#txtModifier4").val();
                    this.DxOption = $("#ddlDxOption").val();
                    this.DxCode1 = $("#txtDx1").val();
                    this.DxCode2 = $("#txtDx2").val();
                    this.DxCode3 = $("#txtDx3").val();
                    this.DxCode4 = $("#txtDx4").val();

                    privateVariables.arrActionData.push(this);

                }
            });
        }
    }
});

// test code ends
Felipe Skinner
  • 16,246
  • 2
  • 25
  • 30
Gaurav Sachdeva
  • 75
  • 2
  • 3
  • 9
  • 1
    _this_ inside jQuery callback functions refers to iterated element – Grundy Jul 01 '15 at 12:09
  • But then why both arrays are getting updated.. Only arrAllDetails should be updated in that case. – Gaurav Sachdeva Jul 01 '15 at 12:11
  • 1
    `privateVariables.arrActionData.push(this);` here you add element from `arrAllDetails` to `privateVariables.arrActionData` so when you update this element - values changes in all arrays, because in array saved just reference to the same object – Grundy Jul 01 '15 at 12:12
  • But I didnt perform any operation on arrAllDetailsConstantData. Why was the object pushed into this array – Gaurav Sachdeva Jul 01 '15 at 12:14
  • you should check how you fill `privateVariables.arrAllDetailsConstantData` and `arrAllDetails` – Grundy Jul 01 '15 at 12:18
  • @Grundy They are filled using the same source. – Gaurav Sachdeva Jul 01 '15 at 12:18
  • so you can use [slice](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice) as suggest @Remi – Grundy Jul 01 '15 at 12:25
  • @Grundy .slice() didnt work as expected. Still I am getting same results. – Gaurav Sachdeva Jul 01 '15 at 12:33
  • yep :-) seems you need deepclone object in array see a bit more [here](http://stackoverflow.com/questions/122102/what-is-the-most-efficient-way-to-clone-an-object) – Grundy Jul 01 '15 at 12:42

3 Answers3

1
  • First, the jQuery's this refers to the calling element.

In a $.each, this refers to the iterated element.

So, in your first loop : $.each(privateVariables.arrAllDetailsConstantData, function() {});, this will be the currently looping element of your arrAllDetailsConstantData array.

In the second loop, this will be the currently looping element of your arrAllDetails array.

  • Secondly, we need the arrays creation's code.

Don't forget, in many languages, that if you use this arrAllDetailsConstantData = arrAllDetails, the pointer reference to those two object are pointing to the same memory range.

In this case, use arrAllDetailsConstantData = arrAllDetails.slice(); from Array.prototype.slice.

Rémi Delhaye
  • 794
  • 3
  • 16
0

for the scope of "this" you can check out JQuery and 'this' object

As for your code: You need to add how you created the two arrays in the first place.

Based on your code they seem to be created by using the same elements (so arrDetails seems to be a subset of the objects in arrAllDetails). Something in the way of

$.each(arrDetails, function() {arrAllDetails.push(this); });

or by simply assinging:

arrDetails = arrAllDetails;

If that is the case then the object within the arrays are actually the SAME. So editing the element in one array will also edit it in the other array (they point to the same object in memory).

I am not sure what you try to accomplish, but if you want the objects to be different you need to clone the entries so they are seperate objects instead of just using them.

Apart from that you basic understanding from this (it applies to the closest scope) is correct, but overridden by other issues.

Community
  • 1
  • 1
Niko
  • 6,133
  • 2
  • 37
  • 49
  • The answer you linked to about jQuery and the 'this' object talks about jQuery event handlers involving a DOM element. That's not really relevant here...in jQuery's `each` function, `this` simply refers to the current item in the array. – Matt Browne Jul 01 '15 at 12:16
  • Yes, U r right. Both arrays are populated using the same source. I have to maintain two array to detect any changes made in UI fields at run time. Any suggestions how can I avoid updating the array arrAllDetailsConstantData – Gaurav Sachdeva Jul 01 '15 at 12:17
  • You can "clone" the array by using: http://api.jquery.com/clone/ that will create a complete separate set. – Niko Jul 01 '15 at 12:26
  • @Niko .clone() doesn't let me proceed neither does it give any exception. – Gaurav Sachdeva Jul 01 '15 at 12:32
  • @Niko any suggesstions?? – Gaurav Sachdeva Jul 01 '15 at 12:56
  • sorry, without seeing more of the code I cannot really help you. You really should try to clone each item in the array: $.each(arrDetails, function() {arrAllDetails.push($.clone(this,true)); }); or if that doe snot work (which it should), try retrieving the data two times or detect the changes in the ui with a different mehtod (i.e. setting the input fields to .addClass('changed') in the onChange event). – Niko Jul 01 '15 at 13:12
0

In Javascript this refers to the owner of a function-execution. It is not always easy to know what the owner actually is. With scoping on HTML-Elements, this usually refers to the elements itself. Inside an iteration (like $.each(data, function)) this refers to the item, that is iterated over.

You use this in 2 different contexts. Each time in another iteration.

$.each(privateVariables.arrAllDetailsConstantData, function() {
    if (this.AssociationId == value && this.uniqueChargeAttr == uniqueChargeAttr) {
        //in this context: "this" refers to the currently selected 
        //item of the iteration over: 
        //  privateVariables.arrAllDetailsConstantData
    } else {
        $.each(arrAllDetails, function() {
            // in this context: "this" refers to the selected item
            // of the iteration over "arrAllDetails"
        });
    }
});

You can preserve the context when entering an iteration by binding this to a local variable.

$.each(privateVariables.arrAllDetailsConstantData, function() {
    if (this.AssociationId == value && this.uniqueChargeAttr == uniqueChargeAttr) {
        // this refers to an item from privateVariables.arrAllDetailsConstantData
    } else {
        var context = this;
        $.each(arrAllDetails, function() {
            // context refers to an item from privateVariables.arrAllDetailsConstantData
            // so: use 
            context.AssociationId
            // instead of 
            this.AssociationId
        });
    }
});
Mathias Vonende
  • 1,400
  • 1
  • 18
  • 28