在Angular中动态插入表中行的正确方法是什么?

时间:2017-10-04 18:53:47

标签: angular

我正在尝试在Angular中的表中插入一行,以显示有关所单击行中对象的信息。数据从服务中获取。我尝试了不同的方法,this one是让我最接近的方法。不幸的是,renderer2.setRootElement()方法删除了单击行的内容。其次,似乎不建议在Angular中使用这样的工作。

模板:

  <tbody #tbody>
    <tr class="row" *ngFor="let ticket of tickets; let i=index"  (click)="createInfoBox($event, i, ticket)" id="row_{{i}}">
    <td class="col-md-1" id="ticket_state"> {{ ticket["AsstDoc.ProcState"] }}</td>
    <td class="col-md-2" id="ticket_date">{{ ticket["AsstDoc.DocDate"] }}</td>
    <td class="col-md-4" id="ticket_office">{{ ticket["AsstDoc.CustName"] }} {{ ticket["AsstDoc.DeliveryAddrNo"] || ticket["Addr.Line1"] }}</td>
    <td class="col-md-4" id="ticket_shortdescr">{{ ticket["AsstDoc.IntermedText"] || ticket["AsstDocItem.IntermedText"] || ticket.json }}</td>
  </tr>
  </tbody>

的onClick:

  createInfoBox($event, index, ticket) {
    this.renderer.selectRootElement(`#row_${index}`).insertAdjacentHTML('afterend', '<tr><td colspan="5">inserted content</td></tr>');
  }

我还尝试了another approach,其中一个指令应该找到所有行并创建一个结果的QueryList,然后我可以从中检索所单击行的索引,并创建一个兄弟。查询列表空了。

@Directive({
  selector: 'tr'
})
export class Rows {
  constructor(public viewContainerRef: ViewContainerRef) { }
}

@ViewChildren(Rows) children: QueryList<Rows>;
ngAfterViewInit() {
  console.log( this.children)
  this.children.changes.subscribe((comps: QueryList <Rows>) =>
  {
    console.log("comps",comps);
  });
}

我今天看到的所有例子让我感到困惑,在我的案例中,正确的做法是什么?

2 个答案:

答案 0 :(得分:1)

您可以将tr包装在ng-template中,然后使用布尔+ ngIf渲染/取消渲染带有其他信息的新行

// component.html
<tbody>
    <ng-container *ngFor="let ticket of tickets">
        <tr (click)="createInfoBox(ticket)">
            <td class="col-md-1">{{ ticket["AsstDoc.ProcState"] }}</td>
            <td class="col-md-2">{{ ticket["AsstDoc.DocDate"] }}</td>
            <td class="col-md-4">{{ ticket["AsstDoc.CustName"] }} {{ ticket["AsstDoc.DeliveryAddrNo"] || ticket["Addr.Line1"] }}</td>
            <td class="col-md-4">{{ ticket["AsstDoc.IntermedText"] || ticket["AsstDocItem.IntermedText"] || ticket.json }}</td>
        </tr>
        <tr *ngIf="ticket.showAdditionalInfo">
            <td colspan="5">inserted content</td>
        </tr>
    </ng-container>
</tbody>

//component.ts
createInfoBox(ticket) {
    // toggle render of additional row
    ticket.showAdditionalInfo = !ticket.showAdditionalInfo;
}

注意:如果要在新行打开时关闭所有打开的行,则需要额外的逻辑

答案 1 :(得分:1)

会像这样工作:

<ng-container *ngFor="let ticket of tickets; let i=index">
<tr class="row" (click)="updateInfoRow($event, i, ticket)" id="row_{{i}}">
    <td class="col-md-1" id="ticket_state"> {{ ticket["AsstDoc.ProcState"] }}    </td>
    <td class="col-md-2" id="ticket_date">{{ ticket["AsstDoc.DocDate"] }}</td>
    <td class="col-md-4" id="ticket_office">{{ ticket["AsstDoc.CustName"] }} {{     ticket["AsstDoc.DeliveryAddrNo"] || ticket["Addr.Line1"] }}</td>
    <td class="col-md-4" id="ticket_shortdescr">{{     ticket["AsstDoc.IntermedText"] || ticket["AsstDocItem.IntermedText"] ||     ticket.json }}</td>
  </tr>
  <tr class="info-row">
     <td>{{infoRows[i].SomeField</td>
     ... more tds ...
  </tr>
</ng-container>

在组件中:

infoRows = [];

ngOnInit() {
  for(int i = 0; i < tickets.length; i++){
     infoRows.push({});
  }
}

updateInfoRow(event, i, ticket) {
  infoRow[i] = { myField, ticket.myField } // or set from the server
}

所以所有行都在那里。您可以隐藏它们,或者*它们,以便它们不会显示,直到点击为止。然后在一个幕后数组中填充数据,您可以根据索引在tr中绑定它。