Skip to content

Commit c10c5a3

Browse files
refactor nesteds in angular
1 parent 819861a commit c10c5a3

1,451 files changed

Lines changed: 19887 additions & 9946 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

packages/devextreme-angular/src/core/component.ts

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import {
1919
createNgModule,
2020
inject,
2121
Injector,
22+
ContentChildren,
2223
} from '@angular/core';
2324

2425
import { isPlatformServer } from '@angular/common';
@@ -36,7 +37,9 @@ import {
3637
INestedOptionContainer,
3738
ICollectionNestedOption,
3839
ICollectionNestedOptionContainer,
39-
CollectionNestedOptionContainerImpl,
40+
CollectionNestedOptionContainerImpl,
41+
_updateNestedItems,
42+
NESTED_ITEM_TOKEN
4043
} from './nested-option';
4144

4245
import { DxIntegrationModule } from './integration';
@@ -47,6 +50,7 @@ config({
4750
});
4851

4952
let serverStateKey;
53+
5054
export const getServerStateKey = () => {
5155
if (!serverStateKey) {
5256
serverStateKey = makeStateKey<any>('DX_isPlatformServer');
@@ -66,6 +70,18 @@ export abstract class DxComponent implements OnChanges, OnInit, DoCheck, AfterCo
6670

6771
private readonly _collectionContainerImpl: ICollectionNestedOptionContainer;
6872

73+
@ContentChildren(NESTED_ITEM_TOKEN)
74+
set _nestedItems(value: QueryList<{ propertyName: string, className: string, component: ICollectionNestedOption}>) {
75+
_updateNestedItems(
76+
value,
77+
this.setChildren.bind(this),
78+
{
79+
componentClassName: this.constructor.name,
80+
legacyClassNames: this.getLegacyClassNames(),
81+
}
82+
);
83+
}
84+
6985
eventHelper: EmitterHelper;
7086

7187
optionChangedHandlers: EventEmitter<any> = new EventEmitter();
@@ -215,13 +231,6 @@ export abstract class DxComponent implements OnChanges, OnInit, DoCheck, AfterCo
215231
}
216232
}
217233

218-
protected _setChildren(propertyName, value, className) {
219-
if (this.checkContentChildren(propertyName, value, className)) {
220-
this.setContentChildren(propertyName, value, className);
221-
this.setChildren(propertyName, value);
222-
}
223-
}
224-
225234
constructor(
226235
protected element: ElementRef,
227236
private readonly ngZone: NgZone,
@@ -306,27 +315,7 @@ export abstract class DxComponent implements OnChanges, OnInit, DoCheck, AfterCo
306315
this.templateUpdateRequired = true;
307316
}
308317

309-
contentChildren = {};
310-
311-
checkContentChildren<T>(propertyName: string, items: QueryList<T>, className: string) {
312-
if (this.contentChildren[propertyName] && this.contentChildren[propertyName] !== className) {
313-
if (items.length > 0) {
314-
if (console && console.warn) {
315-
console.warn(`In ${this.constructor.name},
316-
the nested ${className} and ${this.contentChildren[propertyName]} components are incompatible.
317-
Ensure that all nested components in the content area match.`);
318-
}
319-
}
320-
return false;
321-
}
322-
return true;
323-
}
324-
325-
setContentChildren<T>(propertyName: string, items: QueryList<T>, className: string) {
326-
if (items.length > 0) {
327-
this.contentChildren[propertyName] = className;
328-
}
329-
}
318+
protected getLegacyClassNames: () => Record<string, string[]> = () => ({});
330319

331320
setChildren<T extends ICollectionNestedOption>(propertyName: string, items: QueryList<T>) {
332321
this.resetOptions(propertyName);

packages/devextreme-angular/src/core/nested-option.ts

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
import {
2-
Component, QueryList, ElementRef, Renderer2, EventEmitter,
2+
Component, QueryList, ElementRef, Renderer2, EventEmitter, ContentChildren, InjectionToken,
33
} from '@angular/core';
44

55
import render from 'devextreme/core/renderer';
66
import { triggerHandler } from 'devextreme/events';
77
import domAdapter from 'devextreme/core/dom_adapter';
88
import { getElement } from './utils';
9-
import { DX_TEMPLATE_WRAPPER_CLASS } from './template';
9+
import { DX_TEMPLATE_WRAPPER_CLASS } from './template';
10+
11+
export const NESTED_ITEM_TOKEN = new InjectionToken<string>('nested-item');
1012

1113
const VISIBILITY_CHANGE_SELECTOR = 'dx-visibility-change-handler';
1214

@@ -22,6 +24,49 @@ export interface INestedOptionContainer {
2224

2325
export type IOptionPathGetter = () => string;
2426

27+
const warnAboutIncompatibleNestedItems = (containerClassName: string, itemClassName: string, anotherItemClassName: string) => {
28+
if (console && console.warn) {
29+
console.warn(`In ${containerClassName},
30+
the nested ${itemClassName} and ${anotherItemClassName} components are incompatible.
31+
Ensure that all nested components in the content area match.`);
32+
}
33+
}
34+
35+
export const _updateNestedItems = (
36+
items: QueryList<{ propertyName: string, className: string, component: ICollectionNestedOption}>,
37+
setChildrenFn: (propertyName: string, items: QueryList<ICollectionNestedOption>) => void,
38+
{ componentClassName, legacyClassNames }: { componentClassName: string, legacyClassNames: Record<string, string[]> }
39+
) => {
40+
let hasLegacy = {};
41+
const groupedItems = {}
42+
43+
for (let index = 0; index < items.length; index++) {
44+
const { propertyName, className, component } = items.get(index);
45+
46+
groupedItems[propertyName] = groupedItems[propertyName] || [];
47+
groupedItems[propertyName].push(component);
48+
49+
if (legacyClassNames) {
50+
const isLegacyClassName = legacyClassNames[propertyName].includes(className);
51+
52+
if (index === 0) {
53+
hasLegacy[propertyName] = isLegacyClassName;
54+
} else if (hasLegacy[propertyName] !== isLegacyClassName) {
55+
warnAboutIncompatibleNestedItems(componentClassName, items.get(0).className, className);
56+
return;
57+
}
58+
}
59+
}
60+
61+
Object.entries(groupedItems).forEach(([propertyName, components]: [string, ICollectionNestedOption[]]) => {
62+
const queryList = new QueryList<ICollectionNestedOption>();
63+
64+
queryList.reset(components);
65+
66+
setChildrenFn(propertyName, queryList);
67+
});
68+
};
69+
2570
@Component({
2671
template: '',
2772
})
@@ -202,6 +247,18 @@ export interface ICollectionNestedOption {
202247
export abstract class CollectionNestedOption extends BaseNestedOption implements ICollectionNestedOption {
203248
_index: number;
204249

250+
@ContentChildren(NESTED_ITEM_TOKEN)
251+
set _nestedItems(value: QueryList<{ propertyName: string, className: string, component: ICollectionNestedOption}>) {
252+
_updateNestedItems(
253+
value,
254+
this.setChildren.bind(this),
255+
{
256+
componentClassName: this.constructor.name,
257+
legacyClassNames: null,
258+
}
259+
);
260+
}
261+
205262
protected _fullOptionPath() {
206263
return `${this._getOptionPath()}[${this._index}].`;
207264
}

packages/devextreme-angular/src/ui/accordion/index.ts

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ import {
1616
EventEmitter,
1717
OnChanges,
1818
DoCheck,
19-
SimpleChanges,
20-
ContentChildren,
21-
QueryList
19+
SimpleChanges
2220
} from '@angular/core';
2321

2422
export { ExplicitTypes } from 'devextreme/ui/accordion';
@@ -45,10 +43,6 @@ import { DxiItemModule } from 'devextreme-angular/ui/nested';
4543

4644
import { DxiAccordionItemModule } from 'devextreme-angular/ui/accordion/nested';
4745

48-
import { DxiItemComponent } from 'devextreme-angular/ui/nested';
49-
50-
import { DxiAccordionItemComponent } from 'devextreme-angular/ui/accordion/nested';
51-
5246

5347
/**
5448
* [descr:dxAccordion]
@@ -712,22 +706,20 @@ export class DxAccordionComponent<TItem = any, TKey = any> extends DxComponent i
712706

713707

714708

715-
@ContentChildren(DxiAccordionItemComponent)
716-
get itemsChildren(): QueryList<DxiAccordionItemComponent> {
717-
return this._getOption('items');
718-
}
719-
set itemsChildren(value) {
720-
this._setChildren('items', value, 'DxiAccordionItemComponent');
721-
}
722-
723-
724-
@ContentChildren(DxiItemComponent)
725-
get itemsLegacyChildren(): QueryList<DxiItemComponent> {
726-
return this._getOption('items');
727-
}
728-
set itemsLegacyChildren(value) {
729-
this._setChildren('items', value, 'DxiItemComponent');
730-
}
709+
protected getLegacyClassNames = () => {
710+
const legacyClassNames = {};
711+
712+
const getLegacyClassNamesForPropertyName = (propName) => {
713+
legacyClassNames[propName] = legacyClassNames[propName] || [];
714+
return legacyClassNames[propName];
715+
};
716+
717+
718+
getLegacyClassNamesForPropertyName('items').push('DxiItemComponent');
719+
720+
721+
return legacyClassNames || {};
722+
};
731723

732724

733725

packages/devextreme-angular/src/ui/accordion/nested/item-dxi.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { DOCUMENT } from '@angular/common';
1818

1919

2020
import {
21+
NESTED_ITEM_TOKEN,
2122
DxIntegrationModule,
2223
NestedOptionHost,
2324
extractTemplate,
@@ -27,14 +28,25 @@ import {
2728
} from 'devextreme-angular/core';
2829
import { CollectionNestedOption } from 'devextreme-angular/core';
2930

30-
3131
@Component({
3232
selector: 'dxi-accordion-item',
3333
standalone: true,
3434
template: '<ng-content></ng-content>',
3535
styles: [':host { display: block; }'],
3636
imports: [ DxIntegrationModule ],
37-
providers: [NestedOptionHost, DxTemplateHost]
37+
providers: [
38+
NestedOptionHost,
39+
DxTemplateHost,
40+
{
41+
provide: NESTED_ITEM_TOKEN,
42+
useFactory: (component: DxiAccordionItemComponent) => ({
43+
propertyName: 'items',
44+
className: 'DxiAccordionItemComponent',
45+
component
46+
}),
47+
deps: [DxiAccordionItemComponent],
48+
}
49+
]
3850
})
3951
export class DxiAccordionItemComponent extends CollectionNestedOption implements AfterViewInit,
4052
IDxTemplateHost {
@@ -107,7 +119,6 @@ export class DxiAccordionItemComponent extends CollectionNestedOption implements
107119
return 'items';
108120
}
109121

110-
111122
constructor(@SkipSelf() @Host() parentOptionHost: NestedOptionHost,
112123
@Host() optionHost: NestedOptionHost,
113124
private renderer: Renderer2,

packages/devextreme-angular/src/ui/action-sheet/index.ts

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,7 @@ import {
1616
EventEmitter,
1717
OnChanges,
1818
DoCheck,
19-
SimpleChanges,
20-
ContentChildren,
21-
QueryList
19+
SimpleChanges
2220
} from '@angular/core';
2321

2422
export { ExplicitTypes } from 'devextreme/ui/action_sheet';
@@ -45,10 +43,6 @@ import { DxiItemModule } from 'devextreme-angular/ui/nested';
4543

4644
import { DxiActionSheetItemModule } from 'devextreme-angular/ui/action-sheet/nested';
4745

48-
import { DxiItemComponent } from 'devextreme-angular/ui/nested';
49-
50-
import { DxiActionSheetItemComponent } from 'devextreme-angular/ui/action-sheet/nested';
51-
5246

5347
/**
5448
* [descr:dxActionSheet]
@@ -504,22 +498,20 @@ export class DxActionSheetComponent<TItem = any, TKey = any> extends DxComponent
504498

505499

506500

507-
@ContentChildren(DxiActionSheetItemComponent)
508-
get itemsChildren(): QueryList<DxiActionSheetItemComponent> {
509-
return this._getOption('items');
510-
}
511-
set itemsChildren(value) {
512-
this._setChildren('items', value, 'DxiActionSheetItemComponent');
513-
}
514-
515-
516-
@ContentChildren(DxiItemComponent)
517-
get itemsLegacyChildren(): QueryList<DxiItemComponent> {
518-
return this._getOption('items');
519-
}
520-
set itemsLegacyChildren(value) {
521-
this._setChildren('items', value, 'DxiItemComponent');
522-
}
501+
protected getLegacyClassNames = () => {
502+
const legacyClassNames = {};
503+
504+
const getLegacyClassNamesForPropertyName = (propName) => {
505+
legacyClassNames[propName] = legacyClassNames[propName] || [];
506+
return legacyClassNames[propName];
507+
};
508+
509+
510+
getLegacyClassNamesForPropertyName('items').push('DxiItemComponent');
511+
512+
513+
return legacyClassNames || {};
514+
};
523515

524516

525517

packages/devextreme-angular/src/ui/action-sheet/nested/item-dxi.ts

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import { NativeEventInfo } from 'devextreme/common/core/events';
2020
import { ButtonStyle, ButtonType } from 'devextreme/common';
2121

2222
import {
23+
NESTED_ITEM_TOKEN,
2324
DxIntegrationModule,
2425
NestedOptionHost,
2526
extractTemplate,
@@ -29,14 +30,25 @@ import {
2930
} from 'devextreme-angular/core';
3031
import { CollectionNestedOption } from 'devextreme-angular/core';
3132

32-
3333
@Component({
3434
selector: 'dxi-action-sheet-item',
3535
standalone: true,
3636
template: '<ng-content></ng-content>',
3737
styles: [':host { display: block; }'],
3838
imports: [ DxIntegrationModule ],
39-
providers: [NestedOptionHost, DxTemplateHost]
39+
providers: [
40+
NestedOptionHost,
41+
DxTemplateHost,
42+
{
43+
provide: NESTED_ITEM_TOKEN,
44+
useFactory: (component: DxiActionSheetItemComponent) => ({
45+
propertyName: 'items',
46+
className: 'DxiActionSheetItemComponent',
47+
component
48+
}),
49+
deps: [DxiActionSheetItemComponent],
50+
}
51+
]
4052
})
4153
export class DxiActionSheetItemComponent extends CollectionNestedOption implements AfterViewInit,
4254
IDxTemplateHost {
@@ -101,7 +113,6 @@ export class DxiActionSheetItemComponent extends CollectionNestedOption implemen
101113
return 'items';
102114
}
103115

104-
105116
constructor(@SkipSelf() @Host() parentOptionHost: NestedOptionHost,
106117
@Host() optionHost: NestedOptionHost,
107118
private renderer: Renderer2,

0 commit comments

Comments
 (0)