Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why I can't get result from parent component in Angular

I want child components in angular to separate Material Table(child) from other elements(parent), but the weird thing is that it seems I cannot get data from the parent or I get initialized data from parents and cannot refresh. Here is the Code: firstly, the parent .ts file:

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.scss']
})
export class DashboardComponent implements OnInit{

  ticketList: Ticket[] = [];
  originalTicketList: Ticket[] = [];
  filterAllForm: FormGroup;
  labelList: string[];
  homeLabelList: string[];
  currentTicketId: string;
  searchBy: string = '';
  maxall : number = 100;
  isLoading :boolean = true;
  showRelatedTickets = true;

  constructor(private ticket: TicketService,
    private formBuilder: FormBuilder) { }

  ngOnInit() {
    this.filterAllForm = this.formBuilder.group({
      startDate: [''],
      endDate: ['']
    });
    this.getAllTicket();

  }


  get filterFormControls() { return this.filterAllForm.controls; }



  getAllTicket() {
    let queryParams = '';
    console.log(this.currentTicketId) + " " + this.searchBy;
    if (this.searchBy === 'id') {
      queryParams = 'id=' + this.currentTicketId;
      this.showRelatedTickets = true;
    }else if(this.searchBy !== ''){
      queryParams = this.searchBy + '=' + this.currentTicketId;
      this.showRelatedTickets = false;
    }

    this.ticket.getAllTicket(queryParams).then((res: Ticket[]) => {
      this.isLoading = false;
      this.ticketList = res;
      this.originalTicketList = this.ticketList;
    });
  }


  searchTicket() {
    this.isLoading = true;
    this.getAllTicket();
  }

}

the parent html like this:

    <div class="ticket-container">
      <mat-card *ngIf="isLoading" class="mat-card-style">
        <mat-progress-spinner color="primary" mode="indeterminate">
        </mat-progress-spinner>
      </mat-card>
      <div *ngIf="showRelatedTickets">
        <app-dashboard-related-tickets-table [tablesource]="ticketList">
        </app-dashboard-related-tickets-table>
      </div>
      <div *ngIf="!showRelatedTickets">
        <app-dashboard-non-related-tickets-table [tablesource]="ticketList">
        </app-dashboard-non-related-tickets-table>
      </div>
    </div>

and there are two children you can see, one is app-dashboard-related-tickets-table and another one is app-dashboard-non-related-tickets-table, they have a different format and changed by the button showRelatedTickets. Here I will show the first one the child(app-dashboard-related-tickets-table) .ts file:

@Component({
  selector: 'app-dashboard-related-tickets-table',
  templateUrl: './dashboard-related-tickets-table.component.html',
  styleUrls: ['./dashboard-related-tickets-table.component.scss']
})
export class DashboardRelatedTicketsTableComponent implements OnInit, AfterViewInit{
  dataSource: any;
  displayedDetailColumns = ['id', 'caseStatus', 'anchorPoint', 'findingSourceSystem','caseCreateTimestamp', 'resolvedBy', 'resolution', 'resolutionNote'];
  maxall: number = 100;

  @Input() tablesource: Ticket[];
  @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator;
  @ViewChild(MatSort, { static: true }) sort: MatSort;

  applyFilter(filterValue: string) {
    this.dataSource.filter = filterValue.trim().toLowerCase();

  }
  constructor() { }

  ngOnInit() {
    console.log(this.tablesource);
    this.dataSource = new MatTableDataSource(this.tablesource);
  }

  ngAfterViewInit(){
    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
    this.getPageSizeOptions();
  }

  getPageSizeOptions(): number[] {
    if (this.dataSource.data.length>this.maxall){
      return [20, 50, this.dataSource.data.length];
    }else{
      return [20, 50, this.maxall];
    }
  }

}

then the child(app-dashboard-related-tickets-table) .html file:

<table mat-table matTableExporter [dataSource]="dataSource" matSort class="mat-elevation-z8"
    #exporter="matTableExporter">
    <!-- Ticket Column -->
    <ng-container matColumnDef="id">
        <th mat-header-cell *matHeaderCellDef mat-sort-header class="mat-column-id-source"> SIR ID </th>
        <td mat-cell *matCellDef="let element" class="mat-column-id-source">
            <a href='ticket/{{element.id}}'>{{element.id}}</a>
        </td>
    </ng-container>

    <!-- Type Column event source -->
    <ng-container matColumnDef="findingSourceSystem">
        <th mat-header-cell *matHeaderCellDef mat-sort-header class="mat-column-id-source"> Source </th>
        <td mat-cell *matCellDef="let element" class="mat-column-id-source"> {{element.findingSourceSystem}} </td>
    </ng-container>

    <!-- Type Column Related Event count -->
    <ng-container matColumnDef="anchorPoint">
        <th mat-header-cell *matHeaderCellDef class="mat-column-related-ticket-num"> Related Cases </th>
        <td mat-cell *matCellDef="let element" class="mat-column-related-ticket-num">
            {{element.relatedVertices}} </td>
    </ng-container>

    <!-- Type Column event source -->
    <ng-container matColumnDef="caseStatus">
        <th mat-header-cell *matHeaderCellDef mat-sort-header class="mat-column-case"> Case Status </th>
        <td mat-cell *matCellDef="let element" class="mat-column-case"> {{element.caseStatus}} </td>
    </ng-container>

    <!-- Type Column event source -->
    <ng-container matColumnDef="caseCreateTimestamp">
        <th mat-header-cell *matHeaderCellDef mat-sort-header class="mat-column-date"> Case Created </th>
        <td mat-cell *matCellDef="let element" class="mat-column-date">
            {{element.caseCreateTimestamp | date:'MMM d, y, h:mm:ss a'}}
        </td>
    </ng-container>

    <ng-container matColumnDef="resolvedBy">
        <th mat-header-cell *matHeaderCellDef class="mat-column-resolvedBy"> Resolved By </th>
        <td mat-cell *matCellDef="let element" class="mat-column-resolvedBy"> {{element.resolvedBy}}
        </td>
    </ng-container>

    <ng-container matColumnDef="resolution">
        <th mat-header-cell *matHeaderCellDef class="mat-column-closeCode"> Close Code </th>
        <td mat-cell *matCellDef="let element" class="mat-column-closeCode"> {{element.resolution}}
        </td>
    </ng-container>

    <ng-container matColumnDef="resolutionNote">
        <th mat-header-cell *matHeaderCellDef class="mat-column-closeNote"> Close Note </th>
        <td mat-cell *matCellDef="let element" class="mat-column-closeNote"> {{element.resolutionNote}}
        </td>
    </ng-container>
    <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
    <tr mat-row *matRowDef="let row; columns: displayedColumns;"></tr>
</table>
<mat-paginator [pageSizeOptions]="getPageSizeOptions()" showFirstLastButtons></mat-paginator>
<button mat-raised-button (click)="exporter.exportTable('csv')" class="export-button">Export Results</button>

So in the child component, I use @input tablesource, and display dataSource. but the result is like this: enter image description here

The child component seems loaded because the export result button is already there, but the table didn't show. I just to do

console.log(tablesource)

I got []

This is the browser console log: enter image description here Any Idea what happened?

I was trying to reproduce here: https://stackblitz.com/edit/angular-hbzpvr but I am sorry, I am not good at angular, so I am not sure how to load parent to page.

like image 636
Hongli Bu Avatar asked Dec 25 '19 18:12

Hongli Bu


People also ask

How do we get data from parent components?

To pass data from child to parent component in React:Pass a function as a prop to the Child component. Call the function in the Child component and pass the data as arguments. Access the data in the function in the Parent .

How will you share the data from parent to child component in Angular?

To let Angular know that a property in a child component or directive can receive its value from its parent component we must use the @Input() decorator in the said child. The @Input() decorator allows data to be input into the child component from a parent component.

How do I pass data from parent to child in Angular 12?

Otherwise, remember the three steps: Prepare Child component to emit data. Bind Property in Parent Component template. Use Property in Parent Component class.


1 Answers

According to your console output, you use tablesource in your child component before it has been updated by the parent component. Instead of creating datasource in ngOnInit of the child component, define the tablesource property as a setter and create datasource in that setter:

@Input() set tablesource(value: Ticket[]) {
  console.log(value);
  this.dataSource = new MatTableDataSource(value);
}

See this stackblitz for a demo.

like image 149
ConnorsFan Avatar answered Oct 29 '22 21:10

ConnorsFan