从指令中更改属性

时间:2013-09-06 22:15:47

标签: angularjs

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

指令的链接功能将检查"激活"等于" 1"。如果是这样,它将改变"激活"到0,但做其他一些事情。

稍后,如果我希望指令再次执行某些操作,在控制器中,我将更改"激活"到" 1"再次。由于指令有手表,它将重复循环。

不幸的是,每次我这样做,我都会得到" Expression' 0'用于指令' testDirective'是不可转让的!"或"不可分配的模型表达式: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/

为什么我无法更改指令属性中存储的值?我使用双向绑定。

文档说&#34;如果父作用域属性不存在,则会抛出NON_ASSIGNABLE_MODEL_EXPRESSION异常。&#34;

注意:更新内容正确显示&#34;激活&#34;的值。然而,&#34;激活&#34;的价值in&#34;&#34;没有更新。

然而,这对我来说没有意义,因为父范围属性已存在。

有什么想法吗?

2 个答案:

答案 0 :(得分:12)

虽然我同意使用$watch代替attrs.$observe,但这并不是您收到错误消息的主要原因。

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

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

<test-directive activate="1">

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

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

请参阅下面的代码,我通过控制器在$ 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

答案 1 :(得分: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 here

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

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