有没有办法观察从 AngularJS 世界之外触发的属性更改?
Posted
技术标签:
【中文标题】有没有办法观察从 AngularJS 世界之外触发的属性更改?【英文标题】:Is there a way to watch attribute changes triggered from outside the AngularJS world? 【发布时间】:2013-06-14 02:57:13 【问题描述】:我试图理解 Angular 世界和非 Angular 世界之间的交互。
给定一个这样声明的指令:
<dir1 id="d1" attr1="100"/>
如果 Angular 之外的代码以这种方式更改指令:
$("#d1").attr("attr1", 1000);
指令如何知道它的某个属性发生了变化?
【问题讨论】:
您是上述代码的创建者吗?或者这是一个改变你的 DOM 的外部应用程序?Scope.$apply
可能是您所追求的。不过,您很可能希望将数据交给 Angular 代码,让 Angular 管理 DOM 更改,而不是反过来。
【参考方案1】:
最好在指令内进行此更改。如果由于某种原因无法做到这一点,那么有几种选择。
在应用外部,获取对应用内任何 DOM 元素的引用。使用该引用,您可以获取对其范围的引用。您可以使用 ID 为 d1
的元素。例如:
var domElement = document.getElementById('d1');
var scope = angular.element(domElement).scope();
这里有几个选项:
选项 1
修改模型而不是直接更改视图。在链接函数中,将初始属性值存储在范围变量中,例如:
scope.myvalue = attrs.attr1;
然后您可以更改应用程序外部的值(使用上面对范围的引用),例如:
scope.$apply(function()
scope.myvalue = 1000;
console.log('attribute changed');
);
Here is a fiddle
选项 2
如果直接使用 jQuery 操作视图,我不知道有任何使用 $observe
、$watch
或绑定到将起作用的属性的隔离作用域,因为它们都绑定到属性表达式本身,只有一次,当链接函数第一次运行时。更改值将导致这些绑定失败。所以你必须$watch
DOM 元素本身的属性(而不是通过attrs
):
scope.$watch(function()
return $(el).attr('attr1'); // Set a watch on the actual DOM value
, function(newVal)
scope.message = newVal;
);
然后您可以更改应用程序外部的值(使用上面对范围的引用),例如:
scope.$apply(function()
$("#d1").attr("attr1",1000);
);
Here is a fiddle
【讨论】:
见plnkr.co/edit/ESrh2v1AXBMKOGncg8TS?p=preview。我试过 $apply() 但我无法让它工作。 这其实是无关的; plunk 不起作用,因为即使在指令中更改了属性,$observe
也不会触发。原因在某种程度上隐藏在角度源中:“如果未插入给定属性,则永远不会调用观察者。” (即,如果它不包含括号“”)。尝试在隔离范围内创建绑定并改用 $watch
。
使用$watch()
查看这个新的plunk。这是你的意思吗?它也不起作用。 plnkr.co/edit/uSdbISm3WoNSi7e2ODxQ?p=preview
$watch
需要在一个变量上,现在它在文字 '100' 上(它不会改变,但只会被覆盖)。另外,请注意手动检查在这两种情况下都不起作用。我建议使用变量来存储原始值并直接使用 jQuery 更改变量。 Here is a demo
然后你会说没有办法通知指令其属性之一已通过 DOM 操作发生更改?【参考方案2】:
使用 Web 组件 库,例如 x-tags by Mozilla 或 Polymer by Google。此选项无需在每次属性更改时手动调用 $scope.$apply
即可工作。
我使用 x-tags 是因为它们支持更广泛的浏览器。在定义一个新的自定义标签(指令)时,您可以将选项 lifecycle.attributeChanged
设置为一个回调函数,该函数将在每次参数更改时触发。
The official docs 不是很有帮助。但是通过反复试验和深入研究代码,我设法找出了它是如何工作的。
回调函数的上下文(this
对象)是元素本身。属性发生变化的那个。回调可以接受三个参数:
name
– 属性的名称,
oldValue
和
newValue
– 这些不言自明。
现在,言归正传:
代码
这将观察属性的变化:
xtag.register('dir1',
lifecycle:
attributeChanged: function (attribute, changedFrom, changedTo)
// Find the element's scope
var scope = angular.element(this).scope();
// Update the scope if our attribute has changed
scope.$apply(function ()
if (attribute == 'attr1') scope.style = changedTo;
);
);
attributeChanged
回调仅在参数值实际更改 时触发。要获取它们的初始值,您需要手动扫描批次。最简单的方法似乎是在定义指令时:
myApp.directive('dir1', function ()
return
... ,
link: function (scope, element, attributes)
scope.attr1 = element[0].getAttribute('attr1');
;
);
【讨论】:
以上是关于有没有办法观察从 AngularJS 世界之外触发的属性更改?的主要内容,如果未能解决你的问题,请参考以下文章
有没有办法在 AngularJS 之外重新定义绑定到 $ctrl 的函数?