angularjs1.6 使用$setViewValue无法更新model数值

视图代码

<div ng-controller="appController">
    <div image-uploads ng-model="files"></div>
    <p style="display: block; color: red">{{files}}</p>
</div>

JS代码

var app = angular.module('app', []);
app.controller('appController', function ($scope) {
    $scope.files = '1,2,3,4';
});

app.directive('imageUploads', function () {
    return {
        require: '?^ngModel',
        restrict: 'EA',
        template: '<div class="image-upload-box"><p class="image_upload" ng-repeat="image in images track by $index"><button ng-click="set()">setModel</button><button ng-click="del($index)">{{image}}</button></p></div>',
        link: function ($scope, element, attrs, ngModel) {
            ngModel.$formatters.push(function (modelValue) {
                var images = new Array();
                if (!ngModel.$isEmpty(modelValue)) {
                    var values = modelValue.split(",");
                    for (var j = 0; j < values.length; j++) {
                        images.push({
                            'id': values[j]
                        });
                    }
                }
                return images;
            });

            ngModel.$parsers.push(function (viewValue) {
                var s = "";
                for (var j = 0; j < viewValue.length; j++) {
                    if (viewValue[j].id != null) {
                        if (j > 0) {
                            s += ",";
                        }
                        s += viewValue[j].id;
                    }
                }
                return s;
            });

            ngModel.$render = function () {
                $scope.images = ngModel.$viewValue;
            };

            $scope.del = function (i) {
                $scope.images.splice(i, 1);
                ngModel.$setViewValue($scope.images);
            };
            $scope.set = function () {
                console.log('set');
                $scope.images = [{id: 5}, {id: 6}, {id: 7}];
                ngModel.$setViewValue($scope.images);
            }
        }
    };
});

无法更新Model

使用set函数可以改变ngModel值,并且通过管道函数$parsers,然而del函数使用了splice处理数组,却无法通过管道函数并且实现更新model值。

我尝试过使用$scope.$apply()在ngModel.$setViewValue($scope.images)后执行,依然无法解决。

使用的angular版本为1.6.6。

在线运行代码,在线代码链接,希望大家帮我看下问题到底出现在哪里?

阅读 4.1k
1 个回答

$scope.images是引用变量,在set函数里重新给它赋值了,它指向的内存地址变化了,所以传进$setViewValue后,$setViewValue检测到这个变量变化了所以正常调用了$parsers函数数组等。但是在del函数里只是用splice删除了其中一个元素,$scope.images指向的内存地址没有变化,所以$setViewValue没有检测到这个变量有变化也就不会调用$parsers函数数组了。
在del里splice前加一句:
$scope.images = $scope.images.slice();就行了,复制$scope.images并将$scope.images指向这个复制的内存地址就好了,这样就改变了$scope.images指向的内存地址。

不过话说会来,为什么要搞得这么麻烦呢?应该有更简单的实现方法吧。

推荐问题