为什么我必须调用NgZone.run来查看使用breezejs在Angular2中更新的内容?

时间:2016-04-09 16:26:20

标签: typescript promise angular ecmascript-6 breeze

我正在尝试学习angular2并使用odata webapi后端创建了一个测试应用程序。 在应用程序中,我有一个视图,它获取一个项目数组,我想在我的视图中显示这些。

从前端获取数据我正在使用breezejs库,因为事实证明它在过去节省了很多时间,我喜欢将它与odata后端一起使用。

调用树和应用程序结构如下所示:

通过从视图中调用服务函数开始调用以开始获取项目(请注意,我将从每次调用返回es-6承诺):

this._scrumModuleService.fetchActiveSessions().then((sessions: ScrumSession[]) => {
    // Here i have to call zone.run else my view wont update.
    this._zone.run(() => {
        this.sessions = sessions;
    });
}).catch((error: any) => {
     debugger;
});

然后从视图中它将转到服务,该服务又调用存储库:

public fetchActiveSessions(): Promise<ScrumSession[]> {
    return this._scrumSessionRepository.fetchActiveSessions();
}

存储库获取功能:

public fetchActiveSessions(): Promise<ScrumSession[]> {
    return this._dataContext.fetch(new breeze.EntityQuery().from("ScrumSessions").expand(['creator', 'scrumRoom','productOwner', 'users']));
}

然后最终存储库调用(通用)datacontext,它将使用breeze entitymanager执行查询:

public fetch(query: breeze.EntityQuery, isRetry: boolean = false): Promise<any> {

    return new Promise((resolve, reject) => {
            this.entityManager.executeQuery(query).then((result: breeze.QueryResult): void => {
            // Data has been fetched, resolve the results
            resolve(result.results);
        });
    });
}

现在你可以在视图中看到我必须使用NgZone的run函数,否则我的视图不会更新。我想知道为什么我必须这样做,因为我期待angular2自动为我看到这个。 我已经挖掘了几个类似的问题,但还没找到答案。我还包括了另一个线程中建议的angular2-polyfills脚本,但是没有解决它。

我缺少什么或者我必须实现什么才能让我的视图在不调用zone.run的情况下自动更新?

3 个答案:

答案 0 :(得分:6)

现在,Breeze和Angular2一起运行得很好。我们正在使用当前版本的Breeze和Angular Beta 8开发大型应用程序,没有任何问题。

目前唯一的轻微解决方法是breeze尚未使用Angular2 http提供程序。但是,您可以在默认的“Q”提供程序中进行填充,以便它支持Angular2期望的ES6 Promises,并使用以下代码:

/**
 * Minimum necessary deferred object for breeze Q/ES6 Promise adapter
 * Makes ES6 promise look like Q. 
 */
export interface Deferred {
    promise: Promise<any>;
    resolve: (value?: {} | PromiseLike<{}>) => void;
    reject: (reason?: any) => void;
}

/**
 * Minimum for breeze breeze Q/ES6 Promise adapter
 */
export const Q = {
    defer(): Deferred {
        let resolve: (value?: {} | PromiseLike<{}>) => void;
        let reject: (reason?: any) => void;
        let promise = new Promise((_resolve, _reject) => {
            resolve = _resolve;
            reject = _reject;
        })
        return {
            promise: promise,
            resolve(value: any) { resolve(value); },
            reject(reason: any) { reject(reason); }
        }
    },

    resolve(value?: {} | PromiseLike<{}>) {
        let deferred: Deferred = Q['defer']();
        deferred.resolve(value);
        return deferred.promise;
    },


    reject(reason?: any) {
        let deferred: Deferred = Q['defer']();
        deferred.reject(reason);
        return deferred.promise;
    }
}

然后您可以导入此文件

import { Q } from './q';

然后靠近应用顶部的某个地方

breeze.config.setQ(<breeze.promises.IPromiseService>Q);

此时,所有标准微风方法都与现在完全一样,Angular的变化检测也应该没有问题。

答案 1 :(得分:3)

Angular在修补了大多数异步API的区域中运行。完成异步调用时,Angular运行会更改检测。

以某种方式,微风代码留下了Angulars区域和&#34;休息&#34;改变检测。这可能是因为您从Angular外部初始化breeze或者breeze使用了一些未被Angulars区域修补的异步API,因此回调在Angulars区域外执行。

答案 2 :(得分:3)

是的,“问题”是你使用的是区域不知道的某种承诺库(例如Q)。幸运的是,promise库可以在Breeze中插入,我们编写了一个效果很好的ES6 promise插件。

我们尚未发布它(参见上面的Jay的回答),我们还没有编写Angular 2 http插件。

两者都很容易,但我们一直非常忙碌。看起来好像是时候了。