将“新对象”“附加”到重复项目

时间:2015-03-10 10:34:20

标签: javascript angularjs

我有一个items循环,需要通过API动态替换。问题是外部作用域在替换时似乎松散了对原始对象的引用。如何让外部作用域注意到数组中某个项的值的变化?



(function(ng) {
  'use strict';

  ng.module('app', [])
    .controller('ParentController', ['$scope',
      function($scope) {
        $scope.items = [{
          name: "Foo",
          number: 0
        }, {
          name: "Bar",
          number: 1
        }, {
          name: "Baz",
          number: 1
        }];
      }
    ])
    .controller('ItemController', ['$scope',
      function($scope) {
        // fake code, would get from API normally
        var getFromApi = function() {
          return {
            name: $scope.item.name,
            number: $scope.item.number + 1
          };
        }

        $scope.incr = function() {
          $scope.item = getFromApi();
        }
      }
    ]);
})(window.angular);

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html>

<body ng-app="app">
  <div ng-controller="ParentController">
    <p>When you click one of the below buttons</p>
    <ul>
      <li ng-repeat="item in items" ng-controller="ItemController">
        {{item.name}} ({{item.number}})
        <button ng-click="incr()">+</button>
      </li>
    </ul>
    <p>This should update</p>
    <p>{{items}}</p>
    <p>...but it doesn't</p>
  </div>
</body>

</html>
&#13;
&#13;
&#13;

4 个答案:

答案 0 :(得分:0)

您需要知道该项目的,您要更改其属性,然后更改该集合中的此项。

要声明密钥,您可以使用 ng-repeat="(key, item) in items" 。然后,密钥将在$scope.key中以ItemController显示。

接下来ItemController继承了$scope的{​​{1}},您可以直接访问ParentController中的$scope.items

<强> ItemController.js:

ItemController

只有在ItemController是ParentController的Child或者否则继承它的范围时,这才有可能。

您可以看到脚本运行如下:

$scope.incr = function() {
  $scope.items[$scope.key] = getFromApi();
}
(function(ng) {
  'use strict';

  ng.module('app', [])
    .controller('ParentController', ['$scope',
      function($scope) {
        $scope.items = [{
          name: "Foo",
          number: 0
        }, {
          name: "Bar",
          number: 1
        }, {
          name: "Baz",
          number: 1
        }];
      }
    ])
    .controller('ItemController', ['$scope',
      function($scope) {
        // fake code, would get from API normally
        var getFromApi = function() {
          return {
            name: $scope.item.name,
            number: $scope.item.number + 1
          };
        }



        $scope.incr = function() {
          $scope.items[$scope.key] = getFromApi();
        }
      }
    ]);
})(window.angular);

答案 1 :(得分:0)

您可以使用父数组中项目的索引来替换它

&#13;
&#13;
(function(ng) {
  'use strict';

  ng.module('app', [])
    .controller('ParentController', ['$scope',
      function($scope) {
        $scope.items = [{
          name: "Foo",
          number: 0
        }, {
          name: "Bar",
          number: 1
        }, {
          name: "Baz",
          number: 1
        }];
      }
    ])
    .controller('ItemController', ['$scope',
      function($scope) {
        // fake code, would get from API normally
        var getFromApi = function() {
          return {
            name: $scope.item.name,
            number: $scope.item.number + 1
          };
        }

        $scope.incr = function() {
          $scope.$parent.items[$scope.$index] = getFromApi();
        }
      }
    ]);
})(window.angular);
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html>

<body ng-app="app">
  <div ng-controller="ParentController">
    <p>When you click one of the below buttons</p>
    <ul>
      <li ng-repeat="item in items track by $index" ng-controller="ItemController">
        {{item.name}} ({{item.number}}) {{$index}}
        <button ng-click="incr()">+</button>
      </li>
    </ul>
    <p>This should update</p>
    <p>{{items}}</p>
    <p>...but it doesn't</p>
  </div>
</body>

</html>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

您可以将API调用逻辑移动到父控制器,有关示例,请参阅the JSFiddle demo,或者至少替换父作用域中$scope.items数组中的已修改元素。

编辑:在此处废弃我之前的陈述,但它无效的共鸣是因为当您在子范围$scope.item方法中指定incr()时,您和&#39} #39;不要修改$scope.items数组。您只是在子范围内更改变量赋值。

因此,在incr()调用之前,内存中的变量赋值可能如下所示:

$scope.items =
   item1 -> [ js obj 1 ]
   item2 -> [ js obj 2 ]
   item3 -> [ js obj 3 ]

$scope.item -> [ js obj 1 ]

incr()调用第一项后:

$scope.items =
   item1 -> [ js obj 1 ]       // still obj 1 here!
   item2 -> [ js obj 2 ]
   item3 -> [ js obj 3 ]

$scope.item -> [ js obj 4 ]    // but entirely new obj here!

示例代码:

  angular.module('app', [])
      .controller('ParentController', ['$scope',

  function ($scope) {
      $scope.items = [{
          name: "Foo",
          number: 0
      }, {
          name: "Bar",
          number: 1
      }, {
          name: "Baz",
          number: 1
      }];

      // fake code, would get from API normally
      var getFromApi = function (item) {
          return {
              name: item.name,
              number: item.number + 1
          };
      }

      $scope.updateItem = function (index) {
          $scope.items[index] = getFromApi($scope.items[index]);
      };
  }])
      .controller('ItemController', ['$scope',

  function ($scope) {
      $scope.incr = function (index) {
          $scope.updateItem(index);
      }
  }]);

显然,如果您想以其他方式识别修改后的项目,则可以在不使用$index的情况下离开。上面的代码只是解决您问题的最简单方法。您可能会将getFromApi()保留在子范围内,并在那里使用$scope.items[$index] = getFromApi()(感谢范围继承)。我发现在父范围内保持该方法更加干净。

答案 3 :(得分:0)

另一个(hacky)选项是简单地遍历新对象,分配旧的变量:

var newItem = getFromApi();
for (var key in newItem) {
  $scope.item[key] = newItem[key];
}

&#13;
&#13;
(function(ng) {
  'use strict';

  ng.module('app', [])
    .controller('ParentController', ['$scope',
      function($scope) {
        $scope.items = [{
          name: "Foo",
          number: 0
        }, {
          name: "Bar",
          number: 1
        }, {
          name: "Baz",
          number: 1
        }];
      }
    ])
    .controller('ItemController', ['$scope',
      function($scope) {
        // fake code, would get from API normally
        var getFromApi = function() {
          return {
            name: $scope.item.name,
            number: $scope.item.number + 1
          };
        }

        $scope.incr = function() {
          var newItem = getFromApi();
          for (var key in newItem) {
            $scope.item[key] = newItem[key];
          }
        }
      }
    ]);
})(window.angular);
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<!DOCTYPE html>
<html>

<body ng-app="app">
  <div ng-controller="ParentController">
    <p>When you click one of the below buttons</p>
    <ul>
      <li ng-repeat="item in items" ng-controller="ItemController">
        {{item.name}} ({{item.number}})
        <button ng-click="incr()">+</button>
      </li>
    </ul>
    <p>This should update</p>
    <p>{{items}}</p>
    <p>...now it does!</p>
  </div>
</body>

</html>
&#13;
&#13;
&#13;