Skip to content

Commit c35a1e9

Browse files
Merge pull request #494 from DevExpress/fix_binding
Fix binding for calculated options on initialization
2 parents d3ff145 + 2f3be1e commit c35a1e9

File tree

2 files changed

+55
-10
lines changed

2 files changed

+55
-10
lines changed

src/core/component.ts

Lines changed: 28 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,6 @@ export abstract class DxComponent implements AfterViewInit, INestedOptionContain
4545
this.eventHelper.createEmitter(event.emit, event.subscribe);
4646
});
4747
}
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-
});
53-
}
5448
_shouldOptionChange(name: string, value: any) {
5549
if (this.changedOptions.hasOwnProperty(name)) {
5650
const prevValue = this.changedOptions[name];
@@ -81,10 +75,35 @@ export abstract class DxComponent implements AfterViewInit, INestedOptionContain
8175
}
8276
protected abstract _createInstance(element, options)
8377
protected _createWidget(element: any) {
78+
let events = [];
79+
8480
this._initTemplates();
8581
this._initOptions();
82+
83+
let optionChangeHandler = function(e) {
84+
events.push(e.name);
85+
};
86+
87+
this._initialOptions.onInitializing = function() {
88+
this.on('optionChanged', optionChangeHandler);
89+
};
8690
this.instance = this._createInstance(element, this._initialOptions);
87-
this._initEvents();
91+
92+
this.instance.off('optionChanged', optionChangeHandler);
93+
this.instance.on('optionChanged', (e) => {
94+
this.changedOptions[e.name] = e.value;
95+
this.eventHelper.fireNgEvent(e.name + 'Change', [e.value]);
96+
});
97+
98+
let subsriber = this.ngZone.onStable.subscribe(() => {
99+
subsriber.unsubscribe();
100+
101+
this.ngZone.run(() => {
102+
events.forEach(name => {
103+
this.eventHelper.fireNgEvent(name + 'Change', [this[name]]);
104+
});
105+
});
106+
});
88107
}
89108
protected _destroyWidget() {
90109
if (this.instance) {
@@ -93,12 +112,12 @@ export abstract class DxComponent implements AfterViewInit, INestedOptionContain
93112
element.remove();
94113
}
95114
}
96-
constructor(protected element: ElementRef, ngZone: NgZone, templateHost: DxTemplateHost, private watcherHelper: WatcherHelper) {
115+
constructor(protected element: ElementRef, private ngZone: NgZone, templateHost: DxTemplateHost, private watcherHelper: WatcherHelper) {
97116
this._initialOptions = { integrationOptions: {} };
98117
this.templates = [];
99118
templateHost.setHost(this);
100119
this._collectionContainerImpl = new CollectionNestedOptionContainerImpl(this._setOption.bind(this));
101-
this.eventHelper = new EmitterHelper(ngZone, this);
120+
this.eventHelper = new EmitterHelper(this.ngZone, this);
102121
}
103122
ngAfterViewInit() {
104123
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)