Suspended
Suspended

Reputation: 181

How do I call a method in the non-specific child component from parent component

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?

Upvotes: 0

Views: 644

Answers (2)

Suspended
Suspended

Reputation: 181

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()"

Upvotes: 0

JSmith
JSmith

Reputation: 4808

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.

Upvotes: 0

Related Questions