我需要在指令中观察模型。
angular.module('app', [])
.directive('myDirective', [function() {
return {
restrict: 'A',
scope: {
modelToWatch: '@'
},
link: function(scope, element, attrs) {
scope.$watch(scope.modelToWatch, function(val) {
// do something...
});
}
};
]})
.controller('MyController', ['$scope', function($scope) {
$scope.obj = {
foo: 'val'
};
}]);
<div ng-controller="MyController">
<div my-directive model-to-watch="obj.foo"></div>
</div>
以上工作正常。
但是,当模型的实际所有者与指令之间存在中间范围时,我遇到了问题。
我使用另一个控制器来演示以下场景:
.controller('AnotherController', ['$scope', function($scope) {}])
<div ng-controller="MyController">
<div ng-controller="AnotherController">
<div my-directive model-to-watch="obj.foo"></div>
</div>
</div>
在上面的情况下,我可以使用下面的代码查找$ parent树以查找拥有我想要观看的属性的范围:
...
link: function(scope, element, attrs) {
var contextScope = scope;
// find for the scope which owns the property that we want to watch
while (contextScope != null && contextScope.hasOwnProperty(attrs.modelToWatch)) {
contextScope = contextScope.$parent;
}
// use the scope found to watch the model
if (contextScope != null) {
contextScope.$watch(scope.modelToWatch, function(val) {
// do something...
});
}
}
另外一个问题是,如果modelToWatch是一个复杂的表达式(例如:“tableParams.filter(。。shop_id”),则无法依赖hasOwnProperty。
是否有一种简单的方法可以在其所有者范围内观察模型?或者甚至可以从原型儿童那里观看模型?
或者我可以将范围作为参数传递,所以至少我不需要寻找它......
restrict: 'A',
scope: {
modelToWatch: '@',
sourceScope: '=', // don't know how to do this..
}
注意:我需要使用隔离范围
正如@pixelbit建议的那样,我尝试使用$ eval来找到正确的范围
link: function(scope, element, attrs) {
var contextScope = scope;
// find for the scope which owns the property that we want to watch
while (contextScope != null && contextScope.$eval(attrs.modelToWatch) != undefined) {
contextScope = contextScope.$parent;
}
...
}
适用于大多数情况,除非当modelToWatch表达式实际评估为未定义时。当前范围中不存在modelToWatch(意味着它不是所有者)或者modelToWatch表达式恰好评估为undefined时存在歧义
答案 0 :(得分:0)
不需要隔离范围 - 您可以继承范围。另外,为了解决复杂的表达式,可以使用scope。$ eval来评估模型并找到合适的范围。一旦您对模型进行了评估,请从观察的函数中返回它:
angular.module('app', [])
.directive('myDirective', [function() {
return {
restrict: 'A',
scope: false,
link: function(scope, element, attrs) {
scope.$watch(function() {
return scope.$eval(attrs.modelToWatch);
}, function(val) {
// do something...
});
}
};
]})
如果你必须使用隔离范围,那么观察一个函数并返回模型:
angular.module('app', [])
.directive('myDirective', [function() {
return {
restrict: 'A',
scope: {
modelToWatch: '='
},
link: function(scope, element, attrs) {
scope.$watch(function() {
return scope.modelToWatch;
}, function(val) {
// do something...
});
}
};
]})
答案 1 :(得分:0)
您可以直接在指令中声明控制器:
angular.module('app', [])
.directive('myDirective', [function() {
return {
restrict: 'A',
scope: {
modelToWatch: '='
},
link: function(scope, element, attrs) {
scope.$watch(scope.modelToWatch, function(val) {
// do something...
});
},
controller: 'MyController'
};
]})
.controller('MyController', ['$scope', function($scope) {
$scope.obj = {
foo: 'val'
};
}]);
<div my-directive model-to-watch="obj.foo"></div>
这样,当你调用你的指令时,你的控制器将首先被实例化,然后链接将被执行,共享相同的范围。
答案 2 :(得分:0)
您可以改为观看功能:
scope.$watch(function() {
return scope.modelToWatch;
}, function(val) {
// do something
});