Angular 6 - Ng-Container - Ng-Template inside Mat-

2019-07-24 21:17发布

I am loading data into the mat-table data source from an API. There is an addnewrow() method which would add a new row at the top. I am actually trying to make the first column of the table editable. (i.e) user can give input only if they create a new row. The rest of the data in the table should not be editable. So for that I use a local flag variable false by default. Based on the flag, I am creating ng-template with ng-container.. If it's a new row, the first column is the only editable column, otherwise it should not be editable. I do not know why this is not working.

expected:

  • Only first column of newly added row should be editable
  • save in local storage.

Please check minimal demo - stackblitz, as I don't have rights share actual snippets, my apologies.

Kindly share any working examples and best approach(es) to achieve the goal.

snippet

<table mat-table #methedofaccept [dataSource]="dataSource" class="mat-elevation-z8" id= "tbl">              
  <ng-container *ngIf= "isColumnEditable == true; then showInputField  else normalColumn ">
    <th mat-header-cell *matHeaderCellDef> List of Values </th>
  </ng-container>

  <ng-template #showInputField>
    <td mat-cell matColumnDef="title" *matCellDef="let element" >
      <mat-form-field >
        <input matInput  [value]="element.title" [(ngModel)]="element.title">
      </mat-form-field>
    </td>
  </ng-template>

  <ng-template #normalColumn>
    <div matColumnDef="title">                    
      <td mat-cell *matCellDef="let element"> {{element.title}} </td>
    </div>
  </ng-template>


  <ng-container matColumnDef="action">
    <th mat-header-cell *matHeaderCellDef> Action </th>
    <td mat-cell *matCellDef="let element">                        
      <i *ngIf="element.endDate == null " class="material-icons clickable" (click)="deleteRow(element)">delete</i>
      <i *ngIf="element.endDate != null" class="material-icons clickable ct-blue undo-icon" (click)="undoRow(element)">undo</i>          
    </td>
  </ng-container>
  <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
  <tr mat-row *matRowDef="let row; columns: displayedColumns;" [ngClass]="{'row-deleted': row['isDeleted']" >
  </tr>
</table>

ERROR TypeError: Cannot read property 'template' of undefined

Thank you

1条回答
Lonely孤独者°
2楼-- · 2019-07-24 21:38

What i got from your question:

  1. make first column of table editable i.e. user can give input only if they create new row. rest of the data in table should not be editable
  2. save in local storage.

In your stackblitz, make the table-filtering-example.html to be:

<div class="example-container mat-elevation-z8">


  <mat-table #table [dataSource]="dataSource">

    <!-- Position Column -->
    <ng-container matColumnDef="position">
      <mat-header-cell *matHeaderCellDef> No. </mat-header-cell>
      <mat-cell *matCellDef="let element"> 
        <ng-container *ngIf='element.editable'>
        <input type="number" [(ngModel)]=element.position (ngModelChange)="inputChanged($event)" />
        </ng-container>
        <ng-container *ngIf='!element.editable'>
        {{element.position}} 
        </ng-container>
      </mat-cell>
    </ng-container>

    <!-- Name Column -->
    <ng-container matColumnDef="name">
      <mat-header-cell *matHeaderCellDef> Name </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.name}} </mat-cell>
    </ng-container>

    <!-- Weight Column -->
    <ng-container matColumnDef="weight">
      <mat-header-cell *matHeaderCellDef> Weight </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.weight}} </mat-cell>
    </ng-container>

    <!-- Symbol Column -->
    <ng-container matColumnDef="symbol">
      <mat-header-cell *matHeaderCellDef> Symbol </mat-header-cell>
      <mat-cell *matCellDef="let element"> {{element.symbol}} </mat-cell>
    </ng-container>

    <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
    <mat-row *matRowDef="let row; columns: displayedColumns;"></mat-row>
  </mat-table>
</div>
<button (click)="addNewRow()">Add new row</button>

in your stackblitz, make the table-filtering-example.ts to be:

import { Component, ViewChild,  AfterViewInit } from '@angular/core';
import { MatTableDataSource, MatTable } from '@angular/material';

/**
 * @title Table with filtering
 */
@Component({
  selector: 'table-filtering-example',
  styleUrls: ['table-filtering-example.css'],
  templateUrl: 'table-filtering-example.html',
})
export class TableFilteringExample implements AfterViewInit {
  @ViewChild('table') table: MatTable<Element>;
  displayedColumns = ['position', 'name', 'weight', 'symbol'];
  // dataSource = new MatTableDataSource([]);
  data: Element[] = [];

  constructor(){  
    console.log(this.data);
  }

  ngAfterViewInit(){
    if (this.table){
      //console.log('got table');
      if (this.table.dataSource) {
        this.data = (this.table.dataSource as Element[]);
      }  
      this.data.push(ELEMENT_DATA[this.data.length]);
      this.data.push(ELEMENT_DATA[this.data.length]);
      this.data.push(ELEMENT_DATA[this.data.length]);
      this.data.push(ELEMENT_DATA[this.data.length]);
      this.table.dataSource = this.data;
      this.table.renderRows();
    }
  }

  inputChanged(event){
    this.updateLocalStorage();
  }

  updateLocalStorage(){
      localStorage.setItem('myArray', JSON.stringify(this.table.dataSource) );
  }

  addNewRow() {
    let data: Element[] = [];
    if (this.table.dataSource) {
      data = (this.table.dataSource as Element[]);
    }
    ELEMENT_DATA[data.length].editable =true;
    data.push(ELEMENT_DATA[data.length]);
    this.table.dataSource = data;
    this.table.renderRows();
  }
}

export interface Element {
  name: string;
  position: number;
  weight: number;
  symbol: string;
  editable: boolean;
}

const ELEMENT_DATA: Element[] = [
  {position: 1, name: 'Hydrogen', weight: 1.0079, symbol: 'H', editable: false},
  {position: 2, name: 'Helium', weight: 4.0026, symbol: 'He', editable: false},
  {position: 3, name: 'Lithium', weight: 6.941, symbol: 'Li', editable: false},
  {position: 4, name: 'Beryllium', weight: 9.0122, symbol: 'Be', editable: false},
  {position: 5, name: 'Boron', weight: 10.811, symbol: 'B', editable: false},
  {position: 6, name: 'Carbon', weight: 12.0107, symbol: 'C', editable: false},
  {position: 7, name: 'Nitrogen', weight: 14.0067, symbol: 'N', editable: false},
  {position: 8, name: 'Oxygen', weight: 15.9994, symbol: 'O', editable: false},
  {position: 9, name: 'Fluorine', weight: 18.9984, symbol: 'F', editable: false},
  {position: 10, name: 'Neon', weight: 20.1797, symbol: 'Ne', editable: false},
  {position: 11, name: 'Sodium', weight: 22.9897, symbol: 'Na', editable: false},
  {position: 12, name: 'Magnesium', weight: 24.305, symbol: 'Mg', editable: false},
  {position: 13, name: 'Aluminum', weight: 26.9815, symbol: 'Al', editable: false},
  {position: 14, name: 'Silicon', weight: 28.0855, symbol: 'Si', editable: false},
  {position: 15, name: 'Phosphorus', weight: 30.9738, symbol: 'P', editable: false},
  {position: 16, name: 'Sulfur', weight: 32.065, symbol: 'S', editable: false},
  {position: 17, name: 'Chlorine', weight: 35.453, symbol: 'Cl', editable: false},
  {position: 18, name: 'Argon', weight: 39.948, symbol: 'Ar', editable: false},
  {position: 19, name: 'Potassium', weight: 39.0983, symbol: 'K', editable: false},
  {position: 20, name: 'Calcium', weight: 40.078, symbol: 'Ca', editable: false},
];
查看更多
登录 后发表回答