【问题标题】:Force Angular2 to update model when a 3rd party changes the value of an input using DOM当第 3 方使用 DOM 更改输入值时,强制 Angular2 更新模型
【发布时间】:2017-05-12 20:53:47
【问题描述】:

这是简化的 plunker 示例:

https://plnkr.co/edit/yU9gLsiQJkwsz81H0RBw?p=preview

有一个输入绑定到 val:

<input id="inpt" [(ngModel)]="val"/>

还有一些绑定到同一个 val 的 UI:

<h1>{{val}}</h1>

如果你输入输入,h1 会改变。

该按钮正在扮演第 3 方的角色,它通过以下方式更改输入:

document.getElementById("inpt").value="33";

点击按钮后,h1值没有变为“33”,因为模型还没有更新。

我实际使用的第 3 方是输入字段上的 jqueryui 自动完成功能。

如何强制数据绑定运行(特别是这里需要从 DOM 到模型),以便 UI 的其余部分可以对这种变化做出反应?

您将在 plunker 中看到我试图使用 ngZone 将 document.getElementById("inpt").value ="33" 包装在 ngZone.run 中,但我担心这可能只与模型有关-> DOM 方向。我还看到了更多与更新 DOM 相关的示例。

在 angularjs 中,来自 DOM 的模型更新可以通过以下方式完成: angular.element(this).triggerHandler('input');

【问题讨论】:

    标签: angular data-binding


    【解决方案1】:

    你能做到吗?默认 ngModel 监听输入事件以进行视图->模型更新。

    export function createFakeEvent(type: string) {
      let event = document.createEvent('Event');
      event.initEvent(type, true, true);
      return event;
    }
    
    function dispatchFakeEvent(node: Node | Window, type: string) {
       node.dispatchEvent(createFakeEvent(type));
    } 
    
    do() {
       document.getElementById("inpt").value="33";
       dispatchFakeEvent( document.getElementById("inpt"), 'input');
     }
    

    【讨论】:

    【解决方案2】:

    您可以在do() 方法中处理此问题,如下所示

    do() {
        this.val = "33"
    
      }
    

    Updated plunker

    【讨论】:

    • 我做不到。 plunker 是一个简化的例子。第 3 方实际上是在做改变,而不是我。关键是如果库更改了 DOM,我如何强制更新模型。
    • 只是一些子组件的ngModelngModel
    • 我不明白你的问题
    【解决方案3】:

    您的问题似乎源于使用了候选版本。当前版本按预期工作。 here 你可以看到它按预期工作。

    export class AppComponent { 
      val = 'someThing'
    
      do() {
            document.getElementById("inpt").value="33";
      }
    }
    

    只是工作。 zonejs 通常会检测到这样的事情。但是,如果您的第 3 方做了一些非常出乎意料的事情,并且在当前版本的 Angular 中没有更新,您可以查看changeDetectorRef。您可以使用.markForCheck 或事件.tick 方法来强制进行更改检测。

    【讨论】:

    • 谢谢,桑德。它对我来说没有按预期工作。工作意味着具有“某物”的标签应该更改为“33”,因为它也绑定到“val”。我将研究您提到的其他内容,但首先我将尝试下面的 dispatchFakeEvent。
    • 您也可以通过将代码包装在 setTimeout 中来完成此操作,这样侵入性较小。如果您愿意,我可以修改我的答案以包含该内容?
    • 我的 plunker 现在适合你吗?它在不同的浏览器中对我有用。如果它对您不起作用,我们需要调查发生了什么。
    • 你的 plunker (plnkr.co/edit/tYf4UL?p=preview) 发生了什么变化?它在 Edge 和 Chrome 中仍然对我不起作用(我没有尝试过其他的)。

      在点击按钮后仍然是“someThing”而不是 33。

    猜你喜欢
    • 2018-06-14
    • 1970-01-01
    • 1970-01-01
    • 2017-01-30
    • 1970-01-01
    • 2017-10-22
    • 1970-01-01
    • 2013-12-07
    相关资源
    最近更新 更多