AngularJS - 绑定数组值以输入ngModel

时间:2015-03-25 17:45:20

标签: javascript angularjs

我有$ scope.myArray,并且它通过ngModel和表达式{{myArray}}

与输入字段绑定

我的问题是当我通过调用changeMyArray()修改myArray时,输入的值没有改变。但表达式{{myArray}}显示新值。

那么,为什么表达式工作但输入字段不起作用?

我有办法,但我想找到更好的方法

var newArr = $scope.myArray;
newArr.push("b");
$scope.myArray = angular.copy(newArr);;

Example fiddle

3 个答案:

答案 0 :(得分:4)

基本上,我认为你想要做的是将输入绑定到"新条目"范围变量,然后在用户单击"推送到"时将该变量的值推送到数组。这就是我的意思:

在控制器中:

$scope.changeMyArray = function() {
    $scope.myArray.push($scope.newEntry);
    $scope.newEntry = "";
}

在HTML中:

<input ng-model="newEntry">

但实际上:

你真正想要的是一种通过文本编辑数组内容的方法,并且从其他地方更新该数组也会更新文本。这实际上非常简单,因为浏览器附带了一个JSON库。

我是通过从一对已知对象开始实现的:

$scope.myArray = [];
$scope.myArrayString = "[]";

这样你可以通过ngModel更新字符串:

<input ng-model="myArrayString">

注意此模型的更改以更新实际数组:

$scope.$watch("myArrayString", function() {
    $scope.myArray = JSON.parse($scope.myArrayString);
});

然后更新changeMyArray函数中的字符串:

$scope.changeMyArray = function() {
    $scope.myArray.push("b"); // Or whatever you would like to add here
    $scope.myArrayString = JSON.stringify($scope.myArray);
}

实验in my fork of the Fiddle

发生了什么?

变量$scope.myArray是一个对象,Javascript中的任何对象都可以转换为字符串(大多数复杂对象最终都是无用的"[object Object]")。转换为字符串时,数组实际上会显示其内容,因此通过{{myArray}}将数组绑定到HTML非常简单。

然而,逆向转换并不那么简单。通常,文本输入不能像我们所希望的那样以双向方式绑定到数组。然后,解决方案是使用中间变量来保存字符串值,并使用$scope.$watch来保持两个值同步。

答案 1 :(得分:1)

所以你似乎想知道为什么当推送到数组时,你的$ watch函数没有做增量。这是因为#watch函数只检查对象引用相等性。

当推送到数组时,引用保持不变。复制数组并在同一变量中再次设置时,引用会更改。

这就是为什么@watchCollection按预期工作的原因,并在推送每个项目时递增。

答案 2 :(得分:0)

我对我的问题有解释。如果我错了,请纠正我,非常感谢。

我的问题: 当$ scope.myArray发生更改时,为什么“myArray”输入字段不会更新(Model不更新View)?

<input ng-model="myArray" id="myArray">

答案是AngularJs ng-model不知道$ scope.myArray已更改。因为ng-model不执行对象的深度监视(而不是字符串或数字),所以它只查找标识的更改或比较对象的引用。

就我而言,$ scope.myArray是集合。因此,尽管$ scope.myArray已通过推送新项目(结构已更改)而更改,但它的引用不会更改。

结果,$ setViewValue()和$ render()从未被调用来更新视图。

$render $setViewValue

<强>解决方案:

Sol1:将新项目添加到$ scope.myArray,制作myArray对象的副本,然后再次将副本复制到$ scope.myArray。通过这种方式,对象引用被改变。 AngularJs看到更改并更新视图。

var newArr = $scope.myArray;
newArr.push("b");
$scope.myArray = angular.copy(newArr);

Sol2:创建custome $ watch('email',function(){...}, true )。最后一个参数为TRUE,让Angular执行深度监视。然后,在watch的监听器函数中,我手动设置$ viewValue = newValue并调用ngModelController的$ render()来更新视图。如果我们有Formatters,我们应该在这一步中调用它们。

    $scope.$watch('myArray', function(newValue, oldValue) {
if (newValue !== oldValue) {
        var ctrl = angular.element(document.querySelector('#myArray')).controller('ngModel');

        // Invoke formatter
        var formatters = ctrl.$formatters,
          idx = formatters.length;

        while(idx--) {
            newValue = formatters[idx](newValue);
        }

        ctrl.$render();
  }
    }, true);

Please see my script