【问题标题】:Why is Angular 2's template not updating from calls outside an angular zone?为什么 Angular 2 的模板没有从角度区域外的调用中更新?
【发布时间】:2016-08-10 00:15:25
【问题描述】:

我想我会创建一个非常简单的登录表单,其中包含组件绑定的用户名和密码属性,这些属性将通过以下步骤运行:

  1. 使用 fetch() 调用提交凭据
  2. THEN 获取响应结果对象的 JSON 内容
  3. 然后检查服务器端检查结果的内容

如果凭据错误,它会更改一个组件属性,告诉 Angular 将一个类应用到用户名和密码输入以使它们暂时变为红色(使用 setTimeout 将其改回)

我遇到的问题是 Angular 无法正确应用该类,我不知道为什么。我决定创建一个简化的测试项目来缩小问题范围,最终导致包含 system-polyfills/when.js。

此代码依次经过 1、2、3,并在组件属性中设置它们并将其输出到调试控制台。 Angular 会正确渲染组件属性,除非包含 system-polyfill,在这种情况下,它将停止在 1 并且永远不会将其更改为 2 或 3,即使控制台显示该属性实际上已更改:

export class App {
    private stateIndicator:string = "0";

    public showState(state:string) {
        console.log('State: ' + state);
        this.stateIndicator = state;

    }

    public showFetchProblem() {
        this.showState('1')
        fetch('http://www.google.com/robots.txt',{mode:'no-cors'}).then((response:any) => {
            this.showState('2')
            response.text().then((value) => {
                this.showState('3')
            });
        });
    }
}

我创建了以下 Plunker 来演示这种行为:http://plnkr.co/edit/GR9U9fTctmkSGsPTySAI?p=preview

是的,显而易见的解决方案是:

  1. 不要手动包含 system-polyfills,或者
  2. 如果需要,可以在 SystemJS 之前手动包含不同的 Promise polyfill

但我仍然很好奇为什么会发生这种情况,希望有人能对此有所了解(并可能有助于解决基本问题)。

编辑:最初的标题是Why is Angular 2's template rendering misbehaving when using system-polyfills (when.js)。感谢 Thierry 和 Günter 的贡献并指出 Angular 2 对区域的使用在这里发挥了作用。对于将来遇到这种情况的任何人,这里有两篇优秀的文章,它们更详细地解释了区域,并且在您遇到这种情况时会加深您对这种情况的理解:

  1. http://blog.thoughtram.io/angular/2016/01/22/understanding-zones.html
  2. http://blog.thoughtram.io/angular/2016/02/01/zones-in-angular-2.html

【问题讨论】:

    标签: javascript angular systemjs when-js


    【解决方案1】:

    更新

    不确定解释了,但解决方法有效。但我认为还有其他一些潜在的问题。

    另见https://github.com/angular/angular/issues/7792#issuecomment-211217775

    原创

    我认为问题是由 fetch 未由 Angulars 区域修补引起的

    To work around make the code execute inside Angulars zone manually
    
    export class App {
        constructor(private zone:NgZone) {}
    
        private stateIndicator:string = "0";
    
        public showState(state:string) {
            console.log('State: ' + state);
            this.stateIndicator = state;
    
        }
    
        public showFetchProblem() {
            this.showState('1')
            fetch('http://www.google.com/robots.txt',{mode:'no-cors'}).then((response:any) => {
                this.showState('2')
                response.text().then((value) => {
                    this.zone.run(() => this.showState('3'));
                });
            });
        }
    }
    

    Plunker example

    【讨论】:

      【解决方案2】:

      Promise polyfill 提供了一个自定义的 Promise 实现,它似乎在 Angular2 的范围之外执行(即不在区域中)。

      如果您在 Angular2 管理的区域内显式执行代码(使用 NgZone 类),则在包含 system-polyfill.js 文件时它可以工作。

      这是一个示例:

      constructor(private zone:NgZone) {}
      
      public showFetchProblem() {
        this.showState('1')
        this.zone.run(() => {
          fetch('http://www.google.com/robots.txt',{mode:'no-cors'}).then((response:any) => {
            this.showState('2')
            response.text().then((value) => {
              this.showState('3')
            });
          });
        });
      }
      

      查看对应的plunkr:http://plnkr.co/edit/EJgZKWVx6FURrelMEzN0?p=preview

      【讨论】:

        猜你喜欢
        • 2017-11-07
        • 1970-01-01
        • 1970-01-01
        • 2016-09-14
        • 1970-01-01
        • 1970-01-01
        • 2019-08-14
        • 2018-02-19
        • 1970-01-01
        相关资源
        最近更新 更多