有没有办法观察从 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 – 属性的名称, oldValuenewValue – 这些不言自明。

现在,言归正传:

代码

这将观察属性的变化:

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 的函数?

按下按钮时可观察到 RxSwift 触发器

如何强制视图刷新而不让它从可观察对象自动触发?

有没有办法检测 DOM 节点何时要从 DOM 中删除?

当UiRouter路由改变时观察和显示通知的AngularJS组件

AngularJS - 在 Chrome 中选择文本触发父级中的 ng-click