Skip to content

Commit

Permalink
Event with subscriptions should be fired inside NgZone (#748)
Browse files Browse the repository at this point in the history
* Event with subscriptions should be fired inside NgZone
  • Loading branch information
ovchinnikov committed Apr 13, 2018
1 parent 37670ce commit d8b49f5
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 32 deletions.
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,13 @@
"author": "Developer Express Inc.",
"license": "MIT",
"peerDependencies": {
"devextreme": "~18.1.1-pre-18093",
"devextreme": "~18.1.1-pre-18101",
"@angular/core": ">5.0.0",
"@angular/common": ">5.0.0",
"@angular/forms": ">5.0.0"
},
"devDependencies": {
"devextreme": "~18.1.1-pre-18093",
"devextreme": "~18.1.1-pre-18101",
"zone.js": "^0.8.25",
"@angular/animations": "^5.0.0",
"@angular/common": "^5.0.0",
Expand Down
27 changes: 21 additions & 6 deletions src/core/component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { TransferState, makeStateKey } from '@angular/platform-browser';

import { DxTemplateDirective } from './template';
import { IDxTemplateHost, DxTemplateHost } from './template-host';
import { EmitterHelper } from './events-strategy';
import { EmitterHelper, NgEventsStrategy } from './events-strategy';
import { WatcherHelper } from './watcher-helper';
import * as events from 'devextreme/events';
import {
Expand Down Expand Up @@ -63,7 +63,6 @@ export abstract class DxComponent implements OnChanges, OnInit, DoCheck, AfterCo
});
}
private _initOptions() {
this._initialOptions.eventsStrategy = this.eventHelper.strategy;
this._initialOptions.integrationOptions.watchMethod = this.watcherHelper.getWatchMethod();
}

Expand All @@ -76,9 +75,25 @@ export abstract class DxComponent implements OnChanges, OnInit, DoCheck, AfterCo
}

protected _createEventEmitters(events) {
events.forEach(event => {
this.eventHelper.createEmitter(event.emit, event.subscribe);
});
let ngZone = this.ngZone;
this.eventHelper.createEmitters(events);

this._initialOptions.eventsStrategy = (instance) => {
let strategy = new NgEventsStrategy(ngZone, instance);

events.filter(event => event.subscribe).forEach(event => {
strategy.addEmitter(event.subscribe, this[event.emit]);
});

return strategy;
};

this._initialOptions.nestedComponentOptions = function(component) {
return {
eventsStrategy: (instance) => { return new NgEventsStrategy(ngZone, instance); },
nestedComponentOptions: component.option('nestedComponentOptions')
};
};
}
_shouldOptionChange(name: string, value: any) {
if (this.changedOptions.hasOwnProperty(name)) {
Expand Down Expand Up @@ -156,7 +171,7 @@ export abstract class DxComponent implements OnChanges, OnInit, DoCheck, AfterCo
this.templates = [];
templateHost.setHost(this);
this._collectionContainerImpl = new CollectionNestedOptionContainerImpl(this._setOption.bind(this));
this.eventHelper = new EmitterHelper(this.ngZone, this);
this.eventHelper = new EmitterHelper(this);
}

ngOnChanges(changes: SimpleChanges) {
Expand Down
46 changes: 22 additions & 24 deletions src/core/events-strategy.ts
Original file line number Diff line number Diff line change
@@ -1,33 +1,30 @@
import { EventEmitter, NgZone } from '@angular/core';
import { DxComponent } from './component';

const dxToNgEventNames = {};

interface IEventSubscription {
handler: any;
unsubscribe: () => void;
}

export class NgEventsStrategy {
private subscriptions: { [key: string]: IEventSubscription[] } = {};
private events: { [key: string]: EventEmitter<any> } = {};

constructor(private component: DxComponent, private ngZone: NgZone) { }
constructor(private ngZone: NgZone, private instance: any) { }

hasEvent(name: string) {
return this.ngZone.run(() => {
return this.getEmitter(name).observers.length;
});
return this.getEmitter(name).observers.length;
}

fireEvent(name, args) {
this.ngZone.run(() => {
this.getEmitter(name).next(args && args[0]);
});
let emitter = this.getEmitter(name);
if (emitter.observers.length) {
this.ngZone.run(() => emitter.next(args && args[0]));
}
}

on(name, handler) {
let eventSubscriptions = this.subscriptions[name] || [],
subcription = this.getEmitter(name).subscribe(handler.bind(this.component.instance)),
subcription = this.getEmitter(name).subscribe(handler.bind(this.instance)),
unsubscribe = subcription.unsubscribe.bind(subcription);

eventSubscriptions.push({ handler, unsubscribe });
Expand Down Expand Up @@ -55,32 +52,33 @@ export class NgEventsStrategy {

dispose() {}

public addEmitter(eventName: string, emitter: EventEmitter<any>) {
this.events[eventName] = emitter;
}

private getEmitter(eventName: string): EventEmitter<any> {
let ngEventName = dxToNgEventNames[eventName];
if (!this.component[ngEventName]) {
this.component[ngEventName] = new EventEmitter();
if (!this.events[eventName]) {
this.events[eventName] = new EventEmitter();
}
return this.component[ngEventName];
return this.events[eventName];
}
}

export class EmitterHelper {
strategy: NgEventsStrategy;

constructor(ngZone: NgZone, public component: DxComponent) {
this.strategy = new NgEventsStrategy(component, ngZone);
}
constructor(private component: DxComponent) { }

fireNgEvent(eventName: string, eventArgs: any) {
let emitter = this.component[eventName];
if (emitter) {
emitter.next(eventArgs && eventArgs[0]);
}
}
createEmitter(ngEventName: string, dxEventName: string) {
this.component[ngEventName] = new EventEmitter();
if (dxEventName) {
dxToNgEventNames[dxEventName] = ngEventName;
}

createEmitters(events: any[]) {
events.forEach(event => {
this.component[event.emit] = new EventEmitter();
});
}
}

4 changes: 4 additions & 0 deletions tests/src/ui/list.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -565,6 +565,10 @@ describe('DxList', () => {
expect(onChangesSpy.calls.count()).toBe(0);
instance.element().dispatchEvent(new Event('mouseover'));

expect(onChangesSpy.calls.count()).toBe(0);
let item = instance.element().querySelector('.dx-item');
item.click();

expect(onChangesSpy.calls.count()).toBe(0);
fixture.autoDetectChanges(false);
});
Expand Down

0 comments on commit d8b49f5

Please sign in to comment.