创建具有两行表格的可重复Angular组件

时间:2019-06-20 21:49:46

标签: html angular components

我有两个组成部分。第一个代表项目表,第二个代表一项。第一个重复很多次。

列表组件(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也可以正常工作。

3 个答案:

答案 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);
  }
}

看看Angular lifecycle hooks

答案 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>