Javascript $同时观察多个属性并仅触发一次回调
我想知道在对指令的所有(或仅某些)属性求值之后(没有隔离的作用域),是否可以只执行一次回调。属性非常适合将配置传递给指令。问题是,您可以单独观察每个属性并多次触发回调 在这个例子中,我们有一个没有独立作用域的指令,它观察两个属性:name和names。在触发任何更改Javascript $同时观察多个属性并仅触发一次回调,javascript,angularjs,Javascript,Angularjs,我想知道在对指令的所有(或仅某些)属性求值之后(没有隔离的作用域),是否可以只执行一次回调。属性非常适合将配置传递给指令。问题是,您可以单独观察每个属性并多次触发回调 在这个例子中,我们有一个没有独立作用域的指令,它观察两个属性:name和names。在触发任何更改操作回调后: html <button ng-click="name='John';surname='Brown'">Change all params</button> <div person name
操作
回调后:
html
<button ng-click="name='John';surname='Brown'">Change all params</button>
<div person name="{{name}}" surname="{{surname}}"></div>
所以问题是:
action
是否只能在名称和姓氏值都更改的情况下触发一次?您可以使用$watch
评估自定义函数,而不是特定模型
i、 e
这将在所有$digest
周期上运行,如果$watch
检测到返回数组(或以您希望的方式构造函数的返回值)与旧值不匹配,则将触发$watch
的回调参数。如果确实使用对象作为返回值,请确保将最后一个参数的true
值保留在$watch
中,以便$watch
将进行深入比较。下划线(或短划线)有一个once
函数。如果将函数包装在中一次
,则可以确保函数只被调用一次
angular.module('app',[])。
指令('person',函数(){
返回{
限制:“A”,
链接:函数($scope、$elem、$attrs){
var action=function(){
$elem.append('name:'+$attrs.name+'
姓氏:'+$attrs.姓氏+'
,
);
}
var once=u0.once(操作);
$attrs.$observe('name',一次);
$attrs.$observe(‘姓’,一次);
}
}
});
因此,我最终实现了自己的observeAll
方法,它可以在一个调用堆栈中等待属性的多次更改。它的工作,但我不确定的性能
@cmw的解决方案似乎更简单,但当多次评估对象相等性时,大量参数和多个$digest阶段运行可能会影响性能。然而,我决定接受他的回答
您可以在下面找到我的方法:
angular.module('utils.observeAll', []).
factory('observeAll', ['$rootScope', function($rootScope) {
return function($attrs, callback) {
var o = {},
callQueued = false,
args = arguments,
observe = function(attr) {
$attrs.$observe(attr, function(value) {
o[attr] = value;
if (!callQueued) {
callQueued = true;
$rootScope.$evalAsync(function() {
var argArr = [];
for(var i = 2, max = args.length; i < max; i++) {
var attr = args[i];
argArr.push(o[attr]);
}
callback.apply(null, argArr);
callQueued = false;
});
}
});
};
for(var i = 2, max = args.length; i < max; i++) {
var attr = args[i];
if ($attrs.$attr[attr])
observe(attr);
}
};
}]);
angular.module('utils.observeAll',[])。
工厂('observeAll',['$rootScope',函数($rootScope){
返回函数($attrs,callback){
var o={},
callQueued=false,
args=参数,
观察=功能(attr){
$attrs.$observe(attr,函数(值){
o[attr]=值;
如果(!callQueued){
callQueued=true;
$rootScope.$evalAsync(函数(){
var argArr=[];
对于(变量i=2,max=args.length;i
您可以在指令中使用它:
angular.module('app', ['utils.observeAll']).
directive('person', ['observeAll', function(observeAll) {
return {
restrict: 'A',
link: function($scope, $elem, $attrs) {
var action = function() {
$elem.append('name: ' + $attrs.name + '<br/> surname: ' + $attrs.surname+'<br/><br/>');
}
observeAll($attrs, action, 'name', 'surname');
}
}
}]);
angular.module('app',['utils.observeAll'])。
指令('person',['observeAll',函数(observeAll){
返回{
限制:“A”,
链接:函数($scope、$elem、$attrs){
var action=function(){
$elem.append('name:'+$attrs.name+'
姓氏:'+$attrs.姓氏+'
,
);
}
observeAll($attrs,action,'name','姓氏');
}
}
}]);
Plunker我用另一种方法解决了完全相同的问题,尽管我在寻找不同的想法。当cmw的建议起作用时,我将它的性能与我的进行了比较,发现$watch方法被调用的次数太多了,所以我决定保持我实现的方式 我为我想要跟踪的两个变量添加了$observe调用,并将它们绑定到去盎司调用。由于两个$observe方法都是在时间差很小的情况下修改的,因此两个$observe方法都会触发相同的函数调用,并在短时间延迟后执行:
var debounceUpdate = _.debounce(function () {
setMinAndMaxValue(attrs['minFieldName'], attrs['maxFieldName']);
}, 100);
attrs.$observe('minFieldName', function () {
debounceUpdate();
});
attrs.$observe('maxFieldName', function () {
debounceUpdate();
});
有几种方法可以解决这个问题。我非常喜欢去盎司溶液。然而,这是我对这个问题的解决方案。这将所有属性合并到一个属性中,并创建您感兴趣的属性的JSON表示。现在,你只需要观察一个属性,并有良好的性能了 以下是原始plunkr的分支及其实现:
链接
不幸的是,一旦
将只触发一次回调,但仅在第一个属性更改后才会触发。我的观点是,在单个$digest
阶段的所有更改之后,应该触发回调。
angular.module('utils.observeAll', []).
factory('observeAll', ['$rootScope', function($rootScope) {
return function($attrs, callback) {
var o = {},
callQueued = false,
args = arguments,
observe = function(attr) {
$attrs.$observe(attr, function(value) {
o[attr] = value;
if (!callQueued) {
callQueued = true;
$rootScope.$evalAsync(function() {
var argArr = [];
for(var i = 2, max = args.length; i < max; i++) {
var attr = args[i];
argArr.push(o[attr]);
}
callback.apply(null, argArr);
callQueued = false;
});
}
});
};
for(var i = 2, max = args.length; i < max; i++) {
var attr = args[i];
if ($attrs.$attr[attr])
observe(attr);
}
};
}]);
angular.module('app', ['utils.observeAll']).
directive('person', ['observeAll', function(observeAll) {
return {
restrict: 'A',
link: function($scope, $elem, $attrs) {
var action = function() {
$elem.append('name: ' + $attrs.name + '<br/> surname: ' + $attrs.surname+'<br/><br/>');
}
observeAll($attrs, action, 'name', 'surname');
}
}
}]);
var debounceUpdate = _.debounce(function () {
setMinAndMaxValue(attrs['minFieldName'], attrs['maxFieldName']);
}, 100);
attrs.$observe('minFieldName', function () {
debounceUpdate();
});
attrs.$observe('maxFieldName', function () {
debounceUpdate();
});