Why do i have to call NgZone.run for my view to update in Angular2 with breezejs?
Asked Answered
S

3

9

I am trying to learn angular2 and created a test application with an odata webapi backend. In the application i have a view which fetches an array of items and i want to show these in my view.

For fetching data from the frontend i am using breezejs library since it has proved to save me alot of time in the past and i like using it with an odata backend.

The call tree and application structure looks like this:

Call starts by calling a service function from the view to start fetching the items (note that i am returning an es-6 promise from every call):

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;
});

Then from the view it will go to the service which in turn calls the repository:

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

The repository fetch function:

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

Then eventually the repository calls the (generic) datacontext which will execute the query with the 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);
        });
    });
}

Now as you can see in the view i have to use the run function from NgZone or else my view wont update. I am wondering why i have to do this since i was expecting angular2 to see this for me automatically. I have digged through hseveral similair questions and could not really find an answer yet. I have also included the angular2-polyfills script as suggested in another thread but that did not solve it.

What am i missing or what do i have to implement for my view to update automatically without calling zone.run?

Sutton answered 9/4, 2016 at 16:26 Comment(0)
F
3

Angular runs in a zone where most async APIs are patched. When an async call is completed Angular runs change detection.

Somehow breeze code leaves Angulars zone and "breaks" change detection. This is either because you initialize breeze from outside Angular or breeze uses some async API that is not patched by Angulars zone and therefore callbacks are executed outside Angulars zone.

Flunkey answered 9/4, 2016 at 16:33 Comment(4)
I see, so untill breeze adds support for angular2 would you say its best to just use zone.run for now?Sutton
Yes, use zone.run() and ensure there is a bug report for breeze to get it fixed.Cl
async API that is not patched by Angulars.... I wonder how they do it ? NG already patched timers,callbacks and events. So what kind of other js code can leave the zone?Fraught
The geolocation is a prominent one. Don't know why, perhaps technical difficulties or just lack of resources, ..., or perhaps they fixed that already since. Didn't do much Angular work the last months and didn't follow development.Cl
C
6

Breeze runs just fine with Angular2 now. We are working on a large application using the current version of Breeze and Angular Beta 8 with no problems.

The only slight workaround right now is that breeze does not yet use the Angular2 http provider. However, you can shim in the default 'Q' provider so that it supports the ES6 Promises that Angular2 expects with following code:

/**
 * 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;
    }
}

You can then import this file

import { Q } from './q';

and then somewhere near the top of your app

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

At this point, all of your standard breeze methods work exactly as they do today and Angular's change detection should also have no issues.

Cowell answered 10/4, 2016 at 0:29 Comment(0)
F
3

Angular runs in a zone where most async APIs are patched. When an async call is completed Angular runs change detection.

Somehow breeze code leaves Angulars zone and "breaks" change detection. This is either because you initialize breeze from outside Angular or breeze uses some async API that is not patched by Angulars zone and therefore callbacks are executed outside Angulars zone.

Flunkey answered 9/4, 2016 at 16:33 Comment(4)
I see, so untill breeze adds support for angular2 would you say its best to just use zone.run for now?Sutton
Yes, use zone.run() and ensure there is a bug report for breeze to get it fixed.Cl
async API that is not patched by Angulars.... I wonder how they do it ? NG already patched timers,callbacks and events. So what kind of other js code can leave the zone?Fraught
The geolocation is a prominent one. Don't know why, perhaps technical difficulties or just lack of resources, ..., or perhaps they fixed that already since. Didn't do much Angular work the last months and didn't follow development.Cl
P
3

Yes, the "problem" is that you were using some kind of promise library that zones doesn't know about (e.g. Q). Fortunately the promise library is pluggable in Breeze and we wrote an ES6 promise plugin that works great.

We haven't published it yet (see Jay's answer above) nor have we written the Angular 2 http plugin yet.

Both very easy but we've been super busy. Looks like it's about time.

Pyretotherapy answered 10/4, 2016 at 1:14 Comment(1)
When will you publish the plugin?Reginareginald

© 2022 - 2024 — McMap. All rights reserved.