Skip to content

Commit 23ad1e6

Browse files
Fix binding for calculated options on initialization
1 parent dbeeaca commit 23ad1e6

File tree

2 files changed

+58
-9
lines changed

2 files changed

+58
-9
lines changed

src/core/component.ts

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ export abstract class DxComponent implements AfterViewInit, INestedOptionContain
2424
instance: any;
2525
changedOptions = {};
2626
renderOnViewInit = true;
27+
events = {};
28+
ProcessEvent: Function;
2729

2830
protected _events: { subscribe?: string, emit: string }[];
2931

@@ -45,11 +47,9 @@ export abstract class DxComponent implements AfterViewInit, INestedOptionContain
4547
this.eventHelper.createEmitter(event.emit, event.subscribe);
4648
});
4749
}
48-
private _initEvents() {
49-
this.instance.on('optionChanged', e => {
50-
this.changedOptions[e.name] = e.value;
51-
this.eventHelper.fireNgEvent(e.name + 'Change', [e.value]);
52-
});
50+
private optionChangeHandler(e) {
51+
this.changedOptions[e.name] = e.value;
52+
this.ProcessEvent(e);
5353
}
5454
_shouldOptionChange(name: string, value: any) {
5555
if (this.changedOptions.hasOwnProperty(name)) {
@@ -81,10 +81,33 @@ export abstract class DxComponent implements AfterViewInit, INestedOptionContain
8181
}
8282
protected abstract _createInstance(element, options)
8383
protected _createWidget(element: any) {
84+
let that = this;
85+
8486
this._initTemplates();
8587
this._initOptions();
88+
89+
this.ProcessEvent = function(e) {
90+
that.events[e.name + 'Change'] = [e.value];
91+
};
92+
93+
this._initialOptions.onInitialized = function(e) {
94+
e.component.on('optionChanged', that.optionChangeHandler.bind(that));
95+
};
8696
this.instance = this._createInstance(element, this._initialOptions);
87-
this._initEvents();
97+
98+
this.ProcessEvent = function(e) {
99+
that.eventHelper.fireNgEvent(e.name + 'Change', [e.value]);
100+
};
101+
102+
let subsriber = this.ngZone.onStable.subscribe(() => {
103+
subsriber.unsubscribe();
104+
105+
that.ngZone.run(() => {
106+
for (let key in that.events) {
107+
that.eventHelper.fireNgEvent(key, that.events[key]);
108+
}
109+
});
110+
});
88111
}
89112
protected _destroyWidget() {
90113
if (this.instance) {
@@ -93,12 +116,12 @@ export abstract class DxComponent implements AfterViewInit, INestedOptionContain
93116
element.remove();
94117
}
95118
}
96-
constructor(protected element: ElementRef, ngZone: NgZone, templateHost: DxTemplateHost, private watcherHelper: WatcherHelper) {
119+
constructor(protected element: ElementRef, private ngZone: NgZone, templateHost: DxTemplateHost, private watcherHelper: WatcherHelper) {
97120
this._initialOptions = { integrationOptions: {} };
98121
this.templates = [];
99122
templateHost.setHost(this);
100123
this._collectionContainerImpl = new CollectionNestedOptionContainerImpl(this._setOption.bind(this));
101-
this.eventHelper = new EmitterHelper(ngZone, this);
124+
this.eventHelper = new EmitterHelper(this.ngZone, this);
102125
}
103126
ngAfterViewInit() {
104127
if (this.renderOnViewInit) {

tests/src/core/component.spec.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ let DxTestWidget = DxButton['inherit']({
3030
_render() {
3131
this.callBase();
3232
this.element()[0].classList.add('dx-test-widget');
33+
this.option('testCalculatedOption', 'changed');
3334
}
3435
});
3536

@@ -46,12 +47,20 @@ export class DxTestWidgetComponent extends DxComponent implements AfterViewInit,
4647
set testOption(value: any) {
4748
this._setOption('testOption', value);
4849
};
50+
@Input()
51+
get testCalculatedOption(): any {
52+
return this._getOption('testCalculatedOption');
53+
}
54+
set testCalculatedOption(value: any) {
55+
this._setOption('testCalculatedOption', value);
56+
};
4957

5058
@Output() onOptionChanged = new EventEmitter<any>();
5159
@Output() onInitialized = new EventEmitter<any>();
5260
@Output() onDisposing = new EventEmitter<any>();
5361
@Output() onContentReady = new EventEmitter<any>();
5462
@Output() testOptionChange = new EventEmitter<any>();
63+
@Output() testCalculatedOptionChange = new EventEmitter<any>();
5564

5665
constructor(elementRef: ElementRef, ngZone: NgZone, templateHost: DxTemplateHost, _watcherHelper: WatcherHelper) {
5766
super(elementRef, ngZone, templateHost, _watcherHelper);
@@ -61,7 +70,8 @@ export class DxTestWidgetComponent extends DxComponent implements AfterViewInit,
6170
{ subscribe: 'initialized', emit: 'onInitialized' },
6271
{ subscribe: 'disposing', emit: 'onDisposing' },
6372
{ subscribe: 'contentReady', emit: 'onContentReady' },
64-
{ emit: 'testOptionChange' }
73+
{ emit: 'testOptionChange' },
74+
{ emit: 'testCalculatedOptionChange' }
6575
]);
6676
}
6777

@@ -85,6 +95,8 @@ export class DxTestWidgetComponent extends DxComponent implements AfterViewInit,
8595
export class TestContainerComponent {
8696
visible = true;
8797
testOption: string;
98+
testCalculatedOption = 'initial';
99+
88100
@ViewChildren(DxTestWidgetComponent) innerWidgets: QueryList<DxTestWidgetComponent>;
89101
testMethod() {
90102
}
@@ -349,4 +361,18 @@ describe('DevExtreme Angular widget', () => {
349361
instance.fireEvent('unknownEvent');
350362
}));
351363

364+
it('should detect option changes when option was changed on DX widget creation (T527596)', async(() => {
365+
TestBed.overrideComponent(TestContainerComponent, {
366+
set: {
367+
template: '<dx-test-widget [(testCalculatedOption)]="testCalculatedOption"></dx-test-widget>'
368+
}
369+
});
370+
371+
let fixture = TestBed.createComponent(TestContainerComponent);
372+
fixture.detectChanges();
373+
374+
expect(getWidget(fixture).option('testCalculatedOption')).toBe('changed');
375+
expect(fixture.componentInstance.testCalculatedOption).toBe('changed');
376+
}));
377+
352378
});

0 commit comments

Comments
 (0)