Brk
Brk

Reputation: 1297

One way binding with object angularjs component

Hey I am trying to pass some data in a form of json object from the controller to a component , I using the annotation of '<' and listen to changes on field in the $onChanges method.

But apparently angular sense only one change, although I update the field (data field of current component) every 2 seconds using interval. I have try to use the annotation of '=' but then I can't listen to changes on the object using $onChanges event. So what can I do to solve this problem? Maybe I'm doing something which isn't right.

var app = angular.module("app",[]);
app.component('heroDetail', {
  template: '<span>Name</span>',
  controller: HeroDetailController,
  bindings: {
    data: '<'
  }
});

function HeroDetailController(){
  this.$onChanges = function(changes){
    console.log("changes",changes);
  }
}

app.controller('mainController',function($scope,$interval){
    trendData = {
        Load: [],
        AVGTemperature: [],
        IR: [],
        Acoustic: []
    }
  $interval(function () {
        for (var key in trendData) {
            trendData[key] = [];
            trendData[key].push((new Date()).getTime());
            trendData[key].push(Math.round(Math.random() * 100));
        }
        console.log("$scope.trendData",$scope.trendData)
        $scope.trendData = trendData;
    }, 2000);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div ng-app="app" ng-controller="mainController">
  <hero-detail data="trendData"></hero-detail>
</div>

Upvotes: 0

Views: 1243

Answers (2)

Maciej Sikora
Maciej Sikora

Reputation: 20152

In component architecture common way of passing data between components is to not mutate data but always create new copied structures with new reference. This is only way to monitor data flow in our application, because the easiest and most effective way of checking that something was change is to check only reference without deep checking of every property in object, and this is what exactly component lifecycle is doing.

I must mention that mutating object will refresh the scope in children but will not be monitored as change in component lifecycle. So digest loop will see changes in object, but component lifecycle will not catch those changes.

To fix Your example code to be sure that all changes are monitored by $onChanges we need to create new copy of array on every change. Take a look:

$interval(function () {

    var trendData=$scope.trendData.slice(); //create copy of array
    for (var key in trendData) {
        trendData[key] = [];
        trendData[key].push((new Date()).getTime());
        trendData[key].push(Math.round(Math.random() * 100));
    }
    $scope.trendData = trendData; //we are setting new reference to copied array
}, 2000);

Upvotes: 1

sledsworth
sledsworth

Reputation: 143

Objects that are passed through one-way binding are passed by reference. The $watch that is working behind the scenes does NOT check for object equality, just that the references are the same. This means the $watch is never dirtied and a change will never be picked up. To realize a change to an object you will have to set a watch with the objectEquality flag set in the component. More on this can be found:

https://docs.angularjs.org/api/ng/type/$rootScope.Scope http://blog.kwintenp.com/the-onchanges-lifecycle-hook/

Upvotes: 1

Related Questions