Coherent Coherent - 2 days ago 5
AngularJS Question

In angular updating one variable inexplicably updates another

I am using angular and plotly to plot either the raw data or a moving average. I have the moving average working but I am running into an issue with assigning variables. I retrieve an array of user objects which each have an x and y key with arrays associated with them.

$scope.init=function(){
$rootScope.page='companyResults';
$scope.isPlotlyDone = false;
$scope.moving = false;

var refresh = function () {
incidentService.dayWiseTripsByUser(...).then(function (plotArray){
$scope.unaffectedPlot = plotArray;
$scope.movingAveragePlot = allMoving(plotArray);
console.log($scope.unaffectedPlot[0].y);
console.log($scope.movingAveragePlot[0].y);

});
};

refresh();
}


Im that code block, I would expect that
$scope.unaffectedPlot[0].y
and
$scope.movingAveragePlot[0].y
would have different arrays since I ran the latter through the following set of functions. The curious thing is that both $scope variables are synced, so if I run the second through
allMoving
the
unaffectedPlot
variable also gets smoothed and neither get synced obviously if I don't call
allMoving
. What am I missing about Angular? What is a good way to have a moving average work with a toggle? My plan is to show one variable or the other depending on if a button is clicked.

var d3_numeric = function(x) {
return !isNaN(x);
}

var d3sum = function(array, f) {
var s = 0,
n = array.length,
a,
i = -1;
if (arguments.length === 1) {
// zero and null are equivalent
while (++i < n) if (d3_numeric(a = +array[i])) s += a;
} else {
while (++i < n) if (d3_numeric(a = +f.call(array, array[i], i))) s += a;
}
return s;
};

var movingWindowAvg = function (arr, step) {
return arr.map(function (_, idx) {
var wnd = arr.slice(idx - step, idx + step + 1);
var result = d3sum(wnd) / wnd.length; if (isNaN(result)) { result = _; }
return result;
});
};

var allMoving = function(pltArray) {
var movingArray = [];
pltArray.forEach(function(plot){
var oneMoving = plot;
oneMoving.y = movingWindowAvg(plot.y, 5);
movingArray.push(oneMoving);

});
return movingArray;
}

Dal Dal
Answer

This actually isn't an angular issue. I had to test it some since I didn't see what was going on either.

When you wrote

oneMoving.y = blah

you were actually altering the contents of plot for each element and in turn altering the contents of plotArray unintentionally (since plot is an object) So you are only creating a reference variable when you say 'var onMoving = plot' )

To outright solve your problem you can clone plot but that isn't so clean of a process

One easy yet dirty way is

JSON.parse(JSON.stringify(obj))

from this thread

I threw together a shotty example that captures what was going wrong for you

var array = [{one:1, two:2},{one:1, two:2},{one:1, two:2}],
    copyArray = array,
    newArr = doStuff(array)
function doStuff(a) {
    var otherNewArr = []
    a.forEach(function(ae) {
        var aVar = ae
        aVar.one = 5
        otherNewArr.push(aVar)
    })
    return otherNewArr
}
console.log(copyArray,newArr)

And to fix it just replace

var aVar = ae

with

var aVar = JSON.parse(JSON.stringify(ae))
Comments