Modified data in a factory that's bound to a controller's scope, it doesn't update

百般思念 提交于 2019-12-13 01:13:33

问题


I have a pretty simple example

(also available on this fiddle: http://jsfiddle.net/depov5w6/)

I have 2 factories, one which returns an object with the property 'data', (which is bound to the scope of a controller) and another factory that has 2 methods: populateData and pushData. populateData sets the value of dataSource.data to be a new value. pushData pushes a new value onto dataSource.data

angular.module("app",[])
  .factory('dataSource', function() { 
    return {
      data: ["Init Data"]
    };
  })
  .factory('dataModifier', function(dataSource) { 
    return {
      populateData: function() {
        dataSource.data = ["data from populateData"];
      },
      pushData: function() {
        dataSource.data.push("new data from push data");
      }
    }
  })
  .controller('dataCtrl', function($scope, dataSource, dataModifier) {
    $scope.data = dataSource.data;
    $scope.populateData = dataModifier.populateData;
    $scope.pushData = dataModifier.pushData;
  })

In my view, I have a button that calls pushData and another button that calls populateData. I also display $scope.data

<div ng-app="app">
  <div ng-controller="dataCtrl" class="container">
    <p>Data: {{data}}</p>
    <button ng-click="pushData()">Push Data</button>
    <button ng-click="populateData()">Set Data To New Value</button>
  </div>
</div>

If you look at the fiddle, if you click the Push Data button, new values get pushed onto the array. However, if you click 'Set Data To New Value', nothing happens and subsequent click to push data do nothing. I think I understand that when you click populate data, you lose the reference to the array that $scope.data was bound to, but why doesn't $scope realize that there is a new value for dataSource.data? How would I fix this? I tried making data a private variable, and using getters and setters, but that did nothing.

I appreciate any insight.


回答1:


Instead of assigning data to the scope, assign whole datasource object to the scope & then use it.

Something like: http://jsfiddle.net/depov5w6/1/

.controller('dataCtrl', function($scope, dataSource, dataModifier) {
    $scope.dataSource = dataSource;
    $scope.populateData = dataModifier.populateData;
    $scope.pushData = dataModifier.pushData;
});
<div ng-app="app">
   <div ng-controller="dataCtrl" class="container">
   <p>Data: {{dataSource.data}}</p>
   <button ng-click="pushData()">Push Data</button>
   <button ng-click="populateData()">Set Data To New Value</button>
</div>

The reason this thing works is because of the way angular's dirty checking works. It compares whole objects to detect if there is any change. When you bind a variable to the scope it creates watch on it. If your assign object to the scope it checks object's value to monitor any changes in properties value. So you need to put watch on the property of the object.




回答2:


I think I understand that when you click populate data, you lose the reference to the array that $scope.data was bound to, but why doesn't $scope realize that there is a new value for dataSource.data?

You are correct. When your controller is created (before you have a chance to click the buttons), it points $scope.data to a list in memory that is also pointed to by dataSource.data. Your populateData() function tells dataSource.data to point to a brand new list.. but it doesn't tell $scope.data to stop pointing to the old one.

You could use $scope.$watch() to tell when the reference dataSource.data changes, and then update $scope.data:

.controller('dataCtrl', function($scope, dataSource, dataModifier) {
  $scope.dataSource = dataSource;
  $scope.$watch('dataSource.data', function(data) {
      $scope.data = data;
  });
  $scope.populateData = dataModifier.populateData;
  $scope.pushData = dataModifier.pushData;
})



回答3:


You have to change populateData method like below

  populateData: function() {
    dataSource.data. splice(dataSource.data,dataSource.data.length);
    dataSource.data.push("data from populateData");
  }

Demo



来源:https://stackoverflow.com/questions/25275840/modified-data-in-a-factory-thats-bound-to-a-controllers-scope-it-doesnt-upda

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!