【问题标题】:Angular 2 How to get Angular to detect changes made outside Angular?Angular 2 如何让 Angular 检测在 Angular 之外所做的更改?
【发布时间】:2016-03-26 16:49:36
【问题描述】:

我正在尝试创建一个简单的示例项目来测试 angular 2 更改检测机制:我在主索引页面上的脚本标签中创建了一个纯 javascript 对象。它包含以下内容:

        var Tryout = {};
        Tryout.text = "Original text here";
        Tryout.printme = function(){
            console.log(Tryout.text);
        }
        Tryout.changeme = function(){
            Tryout.text = "Change was made";
        }

一个用于控制台记录的功能,一个用于更改文本属性的功能。

现在在 Angular 2 中,代码如下所示:

import {Component} from "angular2/core"

@Component({
    selector: 'my-app',
    template: `
        <h1>{{TryoutRef.text}}</h1>
        <input type="text" [(ngModel)]="TryoutRef.text">
        <button (click)="consoleLogMe()">Console Log</button>
        <button (click)="changeMe()">Change me inside</button>
    `
})

export class MyApp{

    TryoutRef:any = Tryout;
    constructor(){
    }
    changeMe(){
        this.TryoutRef.changeme();
    }
    consoleLogMe(){
        console.log(this.TryoutRef.text);
    }

}
declare var Tryout:string;

我想要做的是: 当我通常使用 onclick(完全在角度之外)调用函数 Tryout.printme() 时,我希望角度来检测变化并更新屏幕。

我成功地做到了这一点:当我从组件调用 Tryout.printme() 时(changeme() 函数正在调用 Tryout.printme()),Angular 会检测到更改并更新 UI,这很好。此外,当我从外部角度更改并从 Angular 调用 consoleLogMe() 时,它会记录更改的文本并更新 UI。

我想我需要在 Angular 以某种方式运行的同一个区域中执行 Tryout.changeme() 。有任何想法吗?我有一个用纯 javascript/jquery 完成的大项目,现在我需要慢慢地将车把模板重写为 angular2 组件而不触及模型(还)。为此,我需要强制模型在与 angular 相同的区域中执行。

如果我想在 Angular 1 中做这样的事情,我只需要 $scope.$apply 就可以了。

这是示例中的 gif:

【问题讨论】:

  • 为什么Tryout在组件文件中输入string

标签: javascript typescript angular angular2-changedetection


【解决方案1】:

您可以通过在 Angular 应用程序中导出 NgZone 来做到这一点。 通常,你应该在 Angular 中做所有事情,但如果你真的想在 Angular 之外执行你的逻辑,你需要得到正确的zone,正如你所说的。

这个技巧是滥用 Angular 的依赖注入并将注入的 zone 挂钩到 window 对象上,如 this issue 所示。声明对NgZone 的依赖,并将其分配给window.zoneImpl 以进行导出。

//our root app component
import {Component, NgZone} from 'angular2/core'

@Component({
  selector: 'my-app',
  template: `
    <div>
      <h2>Hello {{name}}</h2>

    </div>
  `,
})
export class App {
  constructor(zone: NgZone) {
    this.name = 'Angular2'
    window.app = this
    window.zoneImpl = zone
  }
}

在 Angular 引导之后,您应该有一个 zoneImpl 全局变量。您可以使用 run 方法来启动 Angular。

zoneImpl.run(() =&gt; window.app.name = "new name!")

Live demo.

【讨论】:

  • 另一个快速而丑陋的 hack 是,在引导之后,使用 setTimeout 让 Angular 知道你的代码。 NgZone 已经修补了这个全局函数。
  • 能否请您检查一下 plunkr(消息“:“预览已过期或项目不存在。”)它不见了。
  • 一句警告:确保(如上所示)将您的 window.zoneImpl 变量命名为 other 而不是 window.zone。显然 window.zone 被 Angular 使用,如果你写它,它会搞砸的。
  • 另见Günter's alternative approach:在 Angular 内设置一个事件监听器(因此在 Angular 区域内)。然后在您在 Angular 区域之外进行更改时触发该事件。
  • 我只是将 NgZone 注入到我的所有组件中,并将所有外部回调包装到 ngZone.run(() =&gt; { doSomething(); });
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-11
  • 2017-09-18
  • 1970-01-01
  • 2017-11-17
  • 2017-09-28
相关资源
最近更新 更多