0
votes

Seems I provide too much information, the main question is how can I call a method in the child component from the parent template click() event.

<button(click)='get()'>GET</button>

My parent has his own get(), which is empty. And my child has a customize get(), which is functional. I thought the child's get() will override the parent's because of the extends. But the parents button click() still call the own parent get().

I found some similar solution working with @ViewChild, but my parent is use for many different child component, so I can't declare the @ViewChildproperty like this:

@ViewChild(ChildCmp) child:ChildCmp

The ChildCmp is not specific, I can't declare it with just one child.

If you wanna know my whole skeleton, just keep look the below.

My parent component template like this:

<button(click)='get()'>GET</button>
<h1>{{header}}</h1>
<table mat-table [dataSource]='dataSource'>
    <ng-content></ng-content>

    <tr mat-header-row *matHeaderRowDef='displayedColumns;sticky:true'></tr>
    <tr mat-row *matRowDef='let row;columns:displayedColumns;'></tr>
</table>

parent class like this:

@Component({
  selector: 'app-base-management',
  templateUrl: './base-management.component.html',
  styleUrls: ['./base-management.component.css']
})
export class BaseManagementComponent implements OnInit, AfterContentInit {
  @Input() header = 'this is Header';
  @Input() displayedColumns: string[];
  @Input() dataSource: MatTableDataSource<any>;
  @ViewChild(MatTable, { static: true }) table: MatTable<MatTableDataSource<any>>;
  @ContentChildren(MatColumnDef) columnDefs: QueryList<MatColumnDef>;

  constructor() { }

  ngOnInit(): void { }

  ngAfterContentInit() {
    this.columnDefs.forEach(columnDef => this.table.addColumnDef(columnDef));
  }

  get() { }

}

Also my child component template:

<app-base-management [header]="header" [displayedColumns]="displayedColumns" [dataSource]="dataSource">
  <ng-container matColumnDef="position">
    <th mat-header-cell *matHeaderCellDef> No. </th>
    <td mat-cell *matCellDef="let element; let i= index;">{{cal(i)}} </td>
  </ng-container>

  <ng-container matColumnDef="br_no">
    <th mat-header-cell *matHeaderCellDef> br_no </th>
    <td mat-cell *matCellDef="let element"> {{element.pk_br_no}} </td>
  </ng-container>

  <ng-container matColumnDef="name_tc">
    <th mat-header-cell *matHeaderCellDef> name_tc </th>
    <td mat-cell *matCellDef="let element"> {{element.name_tc}} </td>
  </ng-container>

  <ng-container matColumnDef="name_en">
    <th mat-header-cell *matHeaderCellDef> name_en </th>
    <td mat-cell *matCellDef="let element"> {{element.name_en}} </td>
  </ng-container>
</app-base-management>

My child component class:

@Component({
  selector: 'app-child-a-management',
  templateUrl: './child-a-management.component.html',
  styleUrls: ['./child-a-management.component.css']
})
export class TxpManagementComponent extends BaseManagementComponent implements OnInit {
  displayedColumns: string[] = ['position', 'br_no', 'name_tc', 'name_en'];
  dataSource = new MatTableDataSource<any>();
  header = 'Child A';
  constructor() {}

  ngOnInit(): void {}

  get() {
    ...
    ...
    ...
  }
}

I want to keep the skeleton in the parent, and child store the table column definition and the customize method.

First of all, I thought the get() in child will override the parent's get() for the extends, but it didn't.

And I can't use the solution in this post, because my child component is non-specific, so i can't declare the @viewchild with specific class type.

 @ViewChild(ChildCmp) child:ChildCmp;

call-child-component-method-from-parent-class-angular

How can I call the child's get() from the parent's button click()? Or should I change the skeleton design?

2
Here is no mistake. My child template include the <app-base-management> and emit his own to the parent template <ng-content>Carl Tin
@JSmith This.is my difficulty, the base is not just for the TxpManagementComponent. So I can't declare it with specific TxpManagementComponent type.Carl Tin
@JSmith This problem is not about the template, the template work fine. The matColumnDef is caught by the parent's table and it look good. My question is how the parent's button click() call the child method get() which the child is not specificCarl Tin
@JSmith Just forget the <ng-content> template. I simplify my question, please take a look on the top part.Carl Tin

2 Answers

0
votes

I think your structure is incorrect

see this stackblitz

the key is to have one parent component one child component and a third component calling both

on your parent you'll have to have:

@ContentChild("myEL") myChild;

retrieving <ng-content> whatever maybe the component type

and in the component calling both you shoud have

<app-parent>
  <app-child #myEL>
  </app-child>
</app-parent>

then call in your parent your child function doSomething as so:

doSomethingFromParent(){
  this.myChild.doSomething();
}

of course your if you are using multiple child components type they need to have the function doSomethingdeclared inside one and each of them.

0
votes

Finally found out that I can solve it with EventEmitter.

The base-management component declare

  @Output() getButtonOnClick = new EventEmitter();

And the child component catch it like this

(getButtonOnClick)="get()"