6

使用 AngularJS。我有一个指令,我希望有两种方式的数据绑定。该指令将有一个名为“activate”的属性。最初,“activate”的值为“1”。

该指令的链接函数将检查“activate”是否等于“1”。如果是这样,它将“激活”更改为 0,但会做一些其他的事情。

稍后,如果我想让指令再次做一些事情,在控制器中,我将再次将“激活”更改为“1”。由于指令有手表,它会重复循环。

不幸的是,每次我这样做时,我都会得到“与指令'testDirective'一起使用的表达式'0'是不可分配的!” 或“不可赋值模型表达式:1(指令:testDirective)”。

这是HTML:

<body ng-app="app">
    <test-directive activate="1"></test-directive>    
</body>

这是JS:

var app = angular.module('app', []);


app.directive('testDirective', function() {
    return {
        restrict: 'E',
        scope: {
            activate : '='
        },


        link: function( scope, elem, attrs, controller ) {
            var el = elem[0];

            var updateContent = function() {
                el.innerText = 'Activate=' + scope.activate;
            };

            updateContent();
            attrs.$observe( 'activate', function() {
                console.log('Activate=' + scope.activate);
                if( scope.activate == '1') {
                    scope.activate = '0'
                    updateContent();
                }
            });
        }
    }
});      

这是在 jsFiddle 上:http: //jsfiddle.net/justbn/mgSpY/3/

为什么我不能更改存储在指令属性中的值?我正在使用2路绑定。

文档说“如果父范围属性不存在,它将引发 NON_ASSIGNABLE_MODEL_EXPRESSION 异常。”

注意:更新内容正确显示“激活”的值。但是,“”中“activate”的值不会更新。

然而,这对我来说毫无意义,因为父范围属性确实存在。

有任何想法吗?

4

2 回答 2

12

尽管我同意使用 of$watch而不是attrs.$observe那不是您收到错误消息的主要原因。

问题是您正在尝试将值分配给不可分配的表达式 - 正如错误消息告诉您的那样:Non-assignable model expression: 1 (directive: testDirective)

在这种情况下,不可赋值的表达式是数字“1”

<test-directive activate="1">

您设法将初始值 (1) 传递给指令,但是当指令尝试更新该值时,无法更改属性activate - 因为它是一个数字。

因此,您需要做的就是将其更改为变量,以便稍后更新该值。

请参阅下面的代码,其中我通过控制器在 $scope 中初始化了一个名为 activate.initialValue 的变量。

而且我也用过$watch代替attrs.$observe.

我添加了$timeout只是为了模拟一个事件以在 2 秒后更改激活值。

HTML

<body ng-app="app" ng-controller="appCtrl">
    <test-directive activate="activate.initialValue"></test-directive>    
</body>

JS

var app = angular.module('app', []);

app.controller('appCtrl', function($scope){
    $scope.activate = {
        initialValue : 1
    }
});

var app = angular.module('app', []);

app.controller('appCtrl', function($scope){
    $scope.activate = {
        initialValue : 2
    }
});

app.directive('testDirective', function($timeout) {
    return {
        restrict: 'E',
        scope: {
            activate : '='
        },      
        link: function(scope, elem, attrs) {
            scope.$watch('activate', function(newValue, oldValue){
               console.log('activate has changed', newValue);
            });

             $timeout(function(){ 
                    scope.activate = 0;     
                }, 2000);
        },
        template: "{{activate}}"
    }
});   

您还可以在这里看到工作 ( http://jsfiddle.net/mgSpY/63/ )。

这里是关于它的 AngularJS 官方文档(http://docs.angularjs.org/error/ngModel:nonassign

于 2013-09-06T23:07:22.947 回答
3

要监视范围的属性,您应该使用scope.$watch而不是attrs.$observe

link: function(scope, elem, attrs, controller) {
  var el = elem[0];

  var updateContent = function() {
    el.innerText = 'Activate=' + scope.activate;
  };

  scope.$watch('activate', function(value) {                               
    console.log('Activate=', value);
    if(value === 1) {
      scope.activate = '0'                    
    }
    updateContent();
  });
}

jsFiddle在这里

请注意,我已经updateContent从链接函数中删除了调用,因为您只能在$watch回调中安全地访问范围的属性,除非您可以确保绑定到该属性的值在 Angular 处理指令之前可用。

$observe只能用于观察/观察包含插值的 DOM 属性的值变化(例如,value="{{ value }}")。查看这个SO question以更好地理解它。

于 2013-09-06T22:53:41.040 回答