Skip to content

Commit f129cbe

Browse files
committed
Support dxi components without specified templates
1 parent c518477 commit f129cbe

File tree

5 files changed

+66
-26
lines changed

5 files changed

+66
-26
lines changed

src/core/nested-option.ts

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ export abstract class BaseNestedOption implements INestedOptionContainer, IColle
1515
protected abstract get _optionPath(): string;
1616
protected abstract _fullOptionPath(): string;
1717

18-
constructor(private _element: ElementRef) {
18+
constructor() {
1919
this._collectionContainerImpl = new CollectionNestedOptionContainerImpl(this._setOption.bind(this), this._filterItems.bind(this));
2020
}
2121

@@ -40,11 +40,6 @@ export abstract class BaseNestedOption implements INestedOptionContainer, IColle
4040
this._hostOptionPath = optionPath;
4141
}
4242

43-
_template(...args) {
44-
let container = args[2] || args[1] || args[0];
45-
return container.append(this._element.nativeElement);
46-
}
47-
4843
setChildren<T extends ICollectionNestedOption>(propertyName: string, items: QueryList<T>) {
4944
return this._collectionContainerImpl.setChildren(propertyName, items);
5045
}
@@ -121,6 +116,34 @@ export abstract class CollectionNestedOption extends BaseNestedOption implements
121116
}
122117
}
123118

119+
export interface OptionWithTemplate extends BaseNestedOption {
120+
template: any;
121+
}
122+
export function extractTemplate(option: OptionWithTemplate, element: ElementRef) {
123+
if (!option.template === undefined || !element.nativeElement.hasChildNodes()) {
124+
return;
125+
}
126+
127+
let childNodes = [].slice.call(element.nativeElement.childNodes);
128+
let userContent = childNodes.filter((n) => {
129+
if (n.tagName) {
130+
let tagNamePrefix = n.tagName.toLowerCase().substr(0, 3);
131+
return !(tagNamePrefix === 'dxi' || tagNamePrefix === 'dxo');
132+
} else {
133+
return n.textContent.replace(/\s/g, '').length;
134+
}
135+
});
136+
if (!userContent.length) {
137+
return;
138+
}
139+
140+
option.template = {
141+
render: (options) => {
142+
return options.container.append(element.nativeElement);
143+
}
144+
};
145+
}
146+
124147
export class NestedOptionHost {
125148
private _host: INestedOptionContainer;
126149
private _optionPath: OptionPathGetter;

templates/nested-component.tst

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@
33
import {
44
Component,
55
NgModule,
6-
Host,
6+
Host,<#? it.hasTemplate #>
77
ElementRef,
8+
AfterViewInit,<#?#>
89
SkipSelf<#? it.properties #>,
910
Input<#?#><#? it.collectionNestedComponents.length #>,
1011
ContentChildren,
1112
forwardRef,
1213
QueryList<#?#>
1314
} from '@angular/core';
1415

15-
import { NestedOptionHost } from '../../core/nested-option';
16+
import { NestedOptionHost<#? it.hasTemplate #>, extractTemplate<#?#> } from '../../core/nested-option';
1617
import { <#= it.baseClass #> } from '<#= it.basePath #>';
1718
<#~ it.collectionNestedComponents :component:i #><#? component.className !== it.className #>import { <#= component.className #>Component } from './<#= component.path #>';
1819
<#?#><#~#>
@@ -25,7 +26,7 @@ import { <#= it.baseClass #> } from '<#= it.basePath #>';
2526
'<#= input.name #>'<#? i < it.inputs.length-1 #>,<#?#><#~#>
2627
]<#?#>
2728
})
28-
export class <#= it.className #>Component extends <#= it.baseClass #> {<#~ it.properties :prop:i #>
29+
export class <#= it.className #>Component extends <#= it.baseClass #><#? it.hasTemplate #> implements AfterViewInit<#?#> {<#~ it.properties :prop:i #>
2930
@Input()
3031
get <#= prop.name #>() {
3132
return this._getOption('<#= prop.name #>');
@@ -48,14 +49,16 @@ export class <#= it.className #>Component extends <#= it.baseClass #> {<#~ it.pr
4849
}
4950
<#~#>
5051

51-
constructor(@SkipSelf() @Host() parentOptionHost: NestedOptionHost, @Host() optionHost: NestedOptionHost, element: ElementRef) {
52-
super(element);
53-
<#? it.hasTemplate #>
54-
this.template = this._template.bind(this);
55-
<#?#>
52+
constructor(@SkipSelf() @Host() parentOptionHost: NestedOptionHost, @Host() optionHost: NestedOptionHost<#? it.hasTemplate #>, private element: ElementRef<#?#>) {
53+
super();
5654
parentOptionHost.setNestedOption(this);
5755
optionHost.setHost(this, this._fullOptionPath.bind(this));
5856
}
57+
<#? it.hasTemplate #>
58+
ngAfterViewInit() {
59+
extractTemplate(this, this.element);
60+
}
61+
<#?#>
5962
}
6063

6164
@NgModule({

tests/src/core/nested-option.spec.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,8 @@ export class DxoTestOptionComponent extends NestedOption {
6060
return 'testOption';
6161
}
6262

63-
constructor(@SkipSelf() @Host() private _pnoh: NestedOptionHost, @Host() private _noh: NestedOptionHost, element: ElementRef) {
64-
super(element);
63+
constructor(@SkipSelf() @Host() private _pnoh: NestedOptionHost, @Host() private _noh: NestedOptionHost) {
64+
super();
6565

6666
this._pnoh.setNestedOption(this);
6767
this._noh.setHost(this);
@@ -86,8 +86,8 @@ export class DxiTestCollectionOptionComponent extends CollectionNestedOption {
8686
return 'testCollectionOption';
8787
}
8888

89-
constructor(@SkipSelf() @Host() private _pnoh: NestedOptionHost, @Host() private _noh: NestedOptionHost, element: ElementRef) {
90-
super(element);
89+
constructor(@SkipSelf() @Host() private _pnoh: NestedOptionHost, @Host() private _noh: NestedOptionHost) {
90+
super();
9191

9292
this._pnoh.setNestedOption(this);
9393
this._noh.setHost(this, this._fullOptionPath.bind(this));

tests/src/ui/form.spec.ts

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,7 @@ describe('DxForm', () => {
5050
set: {
5151
template: `
5252
<dx-form id="form" [formData]="formData">
53-
<dxi-item dataField="name" editorType="dxTextBox" [template]="null">
54-
</dxi-item>
53+
<dxi-item dataField="name" editorType="dxTextBox"></dxi-item>
5554
</dx-form>
5655
`
5756
}
@@ -68,12 +67,10 @@ describe('DxForm', () => {
6867
set: {
6968
template: `
7069
<dx-form id="form" [formData]="formData">
71-
<dxi-item caption="Root Group" itemType="group" [template]="null">
72-
<dxi-item dataField="name" editorType="dxTextBox" [template]="null">
73-
</dxi-item>
74-
<dxi-item caption="Inner Group" itemType="group" [template]="null">
75-
<dxi-item dataField="name" editorType="dxTextBox" [template]="null">
76-
</dxi-item>
70+
<dxi-item caption="Root Group" itemType="group">
71+
<dxi-item dataField="name" editorType="dxTextBox"></dxi-item>
72+
<dxi-item caption="Inner Group" itemType="group">
73+
<dxi-item dataField="name" editorType="dxTextBox"></dxi-item>
7774
</dxi-item>
7875
</dxi-item>
7976
</dx-form>

tests/src/ui/list.spec.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,6 +325,23 @@ describe('DxList', () => {
325325
expect(instance.element().find('.dx-item-content').eq(0).text()).toBe('testTemplate');
326326
}));
327327

328+
it('should be able to define item without template', async(() => {
329+
TestBed.overrideComponent(TestContainerComponent, {
330+
set: {
331+
template: `
332+
<dx-list>
333+
<dxi-item text="TestText"></dxi-item>
334+
</dx-list>
335+
`
336+
}
337+
});
338+
let fixture = TestBed.createComponent(TestContainerComponent);
339+
fixture.detectChanges();
340+
341+
let instance = getWidget(fixture);
342+
expect(instance.element().find('.dx-item-content').eq(0).text()).toBe('TestText');
343+
}));
344+
328345

329346
it('should destroy all components inside template', () => {
330347
let destroyed = false;

0 commit comments

Comments
 (0)