为什么我必须调用 NgZone.run 才能使用 breezejs 在 Angular2 中更新我的视图?
Why do i have to call NgZone.run for my view to update in Angular2 with breezejs?
我正在尝试学习 angular2 并创建了一个带有 odata webapi 后端的测试应用程序。
在应用程序中,我有一个视图可以获取一组项目,我想在我的视图中显示这些项目。
为了从前端获取数据,我使用了 breezejs 库,因为它在过去被证明可以节省我很多时间,而且我喜欢将它与 odata 后端一起使用。
调用树和应用程序结构如下所示:
调用从视图中调用服务函数开始获取项目(请注意,我从每次调用中返回一个 es-6 promise):
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 中的 运行 函数,否则我的视图将不会更新。我想知道为什么我必须这样做,因为我期待 angular2 自动为我看到这个。
我已经研究了几个类似的问题,但还没有真正找到答案。我还按照另一个线程中的建议包含了 angular2-polyfills 脚本,但这并没有解决它。
我缺少什么或者我必须实现什么才能让我的视图在不调用 zone.run 的情况下自动更新?
Angular 在大多数异步 API 已打补丁的区域中运行。异步调用完成后 Angular 运行更改检测。
不知何故 breeze 代码离开 Angulars 区域和 "breaks" 变化检测。这是因为您从 Angular 外部初始化 breeze 或 breeze 使用了一些未被 Angulars 区域修补的异步 API,因此回调在外部执行Angulars 区。
Breeze 现在在 Angular2 上运行得很好。我们正在使用当前版本的 Breeze 和 Angular Beta 8 开发大型应用程序,没有任何问题。
目前唯一的解决方法是 breeze 尚未使用 Angular2 http 提供程序。但是,您可以填充默认的 'Q' 提供程序,以便它支持 Angular2 期望使用以下代码的 ES6 Promise:
/**
* 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);
此时,您所有的标准 breeze 方法都像今天一样工作,Angular 的变化检测也应该没有问题。
是的,"problem" 是您使用了某种区域不知道的承诺库(例如 Q)。幸运的是,promise 库在 Breeze 中是可插入的,我们编写了一个运行良好的 ES6 promise 插件。
我们还没有发布它(参见上面 Jay 的回答),我们也没有编写 Angular 2 http
插件。
两者都很容易,但我们一直非常忙。看来是时候了。
我正在尝试学习 angular2 并创建了一个带有 odata webapi 后端的测试应用程序。 在应用程序中,我有一个视图可以获取一组项目,我想在我的视图中显示这些项目。
为了从前端获取数据,我使用了 breezejs 库,因为它在过去被证明可以节省我很多时间,而且我喜欢将它与 odata 后端一起使用。
调用树和应用程序结构如下所示:
调用从视图中调用服务函数开始获取项目(请注意,我从每次调用中返回一个 es-6 promise):
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 中的 运行 函数,否则我的视图将不会更新。我想知道为什么我必须这样做,因为我期待 angular2 自动为我看到这个。 我已经研究了几个类似的问题,但还没有真正找到答案。我还按照另一个线程中的建议包含了 angular2-polyfills 脚本,但这并没有解决它。
我缺少什么或者我必须实现什么才能让我的视图在不调用 zone.run 的情况下自动更新?
Angular 在大多数异步 API 已打补丁的区域中运行。异步调用完成后 Angular 运行更改检测。
不知何故 breeze 代码离开 Angulars 区域和 "breaks" 变化检测。这是因为您从 Angular 外部初始化 breeze 或 breeze 使用了一些未被 Angulars 区域修补的异步 API,因此回调在外部执行Angulars 区。
Breeze 现在在 Angular2 上运行得很好。我们正在使用当前版本的 Breeze 和 Angular Beta 8 开发大型应用程序,没有任何问题。
目前唯一的解决方法是 breeze 尚未使用 Angular2 http 提供程序。但是,您可以填充默认的 'Q' 提供程序,以便它支持 Angular2 期望使用以下代码的 ES6 Promise:
/**
* 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);
此时,您所有的标准 breeze 方法都像今天一样工作,Angular 的变化检测也应该没有问题。
是的,"problem" 是您使用了某种区域不知道的承诺库(例如 Q)。幸运的是,promise 库在 Breeze 中是可插入的,我们编写了一个运行良好的 ES6 promise 插件。
我们还没有发布它(参见上面 Jay 的回答),我们也没有编写 Angular 2 http
插件。
两者都很容易,但我们一直非常忙。看来是时候了。