我有两个组成部分。第一个代表项目表,第二个代表一项。第一个重复很多次。
列表组件(app-list
):
<table>
<tr *ngFor="let item of items" [item]="item" app-item></tr>
</table>
项目组件(app-item
):
<td>
<img src="https://someimage.com/{{item.img}}.jpg">
</td>
<td>
<h3>{{item.name}}</h3>
</td>
<td>
{{item.description}}
</td>
为此,我必须为app-item
组件使用属性选择器:
@Component({
selector: '[app-item]'
})
这很好用。
现在,我想对其进行改进,并在每个app-item
中添加第二行。我的问题是tr
标签位于app-list
组件而不是app-item
组件中。我认为,如果将其移至app-item
组件,则可以添加另一个tr
并能够在一项中显示两行。这就是我所做的。之后,为了避免在两行之间添加包装标签,我使用ng-container
重复了app-list
中的项目:
<ng-container *ngFor="let item of items" [item]="item" app-item></ng-container>
此解决方案无效。我收到以下错误:
ERROR TypeError: el.setAttribute is not a function
at EmulatedEncapsulationDomRenderer2.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.DefaultDomRenderer2.setAttribute (platform-browser.js:1089)
at EmulatedEncapsulationDomRenderer2.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.EmulatedEncapsulationDomRenderer2.applyToHost (platform-browser.js:1157)
at DomRendererFactory2.push../node_modules/@angular/platform-browser/fesm5/platform-browser.js.DomRendererFactory2.createRenderer (platform-browser.js:1015)
您能帮助我解决此错误或建议其他实现吗?
编辑:解决方案
@Serhiy建议的更好版本
表格:
<table>
<app-item *ngFor="let item of items" [item]="item" remove-component-tag></app-item>
</table>
指令:
import { Directive, ElementRef } from '@angular/core';
@Directive({
selector: '[remove-component-tag]'
})
export class RemoveComponentTagDirective {
constructor(private el: ElementRef) {
let element = el.nativeElement;
let children = el.nativeElement.childNodes;
setTimeout(()=>{
let reversedChildren = [];
children.forEach(child => {
reversedChildren.unshift(child);
});
reversedChildren.forEach(child => {
element.parentNode.insertBefore(child, element.nextSibling);
});
element.remove(element);
}, 0);
}
}
出于某些原因,超时是必需的,即使使用0也可以正常工作。
答案 0 :(得分:3)
我看不到正确的“角度”方式,但是您应该能够在渲染过程中使用指令清除html。
在此处的评论中看到了这种方法:Angular2 : render a component without its wrapping tag
我尝试过,对我有用:
父组件:
<table>
<div *ngFor="let item of items">
<app-item [item]="item" remove-wrapper></app-item>
</div>
</table>
子组件:
<tr>
<td>
<img src="https://someimage.com/{{item.img}}.jpg">
</td>
<td>
<h3>{{item.name}}</h3>
</td>
<td>
{{item.description}}
</td>
</tr>
<tr>
<td>
<img src="https://someimage.com/{{item.img}}.jpg">
</td>
<td>
<h3>{{item.name + ' 2'}}</h3>
</td>
<td>
{{item.description + ' 2'}}
</td>
</tr>
指令:
@Directive({
selector: '[remove-wrapper]'
})
export class RemoveWrapperDirective {
constructor(private el: ElementRef) {
let parent = el.nativeElement.parentElement;
let children = el.nativeElement.childNodes;
setTimeout(()=>{
parent.parentNode.insertBefore(children[1], parent.nextSibling);
parent.parentNode.insertBefore(children[0], parent.nextSibling);
parent.remove(parent);
}, 10);
}
}
没有超时,它对我崩溃了。可以改进代码,但是您可以从这里开始。
答案 1 :(得分:1)
感谢您的解决方案。
我想为您的代码添加一个更正,以避免使用setTimeout
函数。
为指令实现OnInit
接口,并将代码从构造函数移至ngOnInit
方法,将保持代码干净。
import { Directive, OnInit, ElementRef } from '@angular/core';
@Directive({
selector: '[remove-component-tag]'
})
export class RemoveComponentTagDirective implements OnInit{
constructor(private el: ElementRef) { }
ngOnInit() {
let element = this.el.nativeElement;
let children = this.el.nativeElement.childNodes;
let reversedChildren = [];
children.forEach(child => {
reversedChildren.unshift(child);
});
reversedChildren.forEach(child => {
element.parentNode.insertBefore(child, element.nextSibling);
});
element.remove(element);
}
}
答案 2 :(得分:0)
在这里会使用组件语法而不是指令语法吗?
代替:
<ng-container *ngFor="let item of items" [item]="item" app-item></ng-container>
尝试:
<ng-container *ngFor="let item of items">
<app-item [item]="item"></app-item>
</ng-container>