user2294434
user2294434

Reputation: 163

How to call child components method from parent component

I have a parent-child component as below. Inside child.compontent.ts, I have a method : childFunction(). I want to call this method inside parent's function. How to achieve this ?

**Parent.html :** 

<div class="box">
    <input type="text" (input)="searchValue=$event.target.value" placeholder={{placeHolder}} />
    
<btn-icon [searchType]='searchType' [searchText]='searchValue'></btn-icon> // child component
</div>

**parent.component.ts :**

export class parentComponent implements OnInit {

parentFunction(){
// **Call** childFunction('inputValue');

}
 
**btn-icon  is Child :**
**btn-icon.component.ts:  (Child)**

export class btn-iconimplements OnInit {
  
  @Input() Type: string;
  @Input() Text: string;

childFunction(inputValue){
      //some logic
    }
}
 

Upvotes: 1

Views: 11496

Answers (4)

Adnan Omerovic
Adnan Omerovic

Reputation: 1

Callback pattern could bring us another solution for this problem. Working solution available on stackblitz: https://stackblitz.com/edit/angular-e6hakq

Child component

@Component({
  selector: 'app-child',
  template: `<div>
    <h3>Child var: {{num}}!</h3>
  </div>`,
})
export class ChildComponent implements OnDestroy {
  protected num: number = 0;
  private _param: ParamFn | null = null;

  get param() {
    return this._param;
  }

  @Input() set param(val: ParamFn) {
    this._param = val;
    this._param.registerFn(this.innerComponentFunction);
  }

  private innerComponentFunction = () => {
    this.num++;
  };

  ngOnDestroy() {
    if (this.param) {
      //avoid memory leak
      this.param.deregisterFn();
      this.param.deregisterFn = null;
      this.param.registerFn = null;
    }
  }
}


export type ParamFn =  {
  registerFn: (callback: () => void) => void,
  deregisterFn: () => void
}

Parent component

@Component({
  selector: 'app-parent',
  template: `<app-child 
    [param]="fnParam"></app-child>
    <button (click)="invokeChildFn()">Trigger Child Function</button>
    `,
})
export class ParentComponent {
  private childFn: Function | null = null;

  registerDeactivateChildFunction = (func: () => void) => {
    this.childFn = func;
  };

  deregisterFunction = () => {
    this.childFn = null;
    console.log('deregisterFunction parent');
  };

  protected fnParam: ParamFn = {
    registerFn: this.registerDeactivateChildFunction.bind(this),
    deregisterFn: this.deregisterFunction.bind(this),
  };

  protected invokeChildFn() {
    if (this.childFn) {
      this.childFn();
    }
  }

Upvotes: 0

DonJuwe
DonJuwe

Reputation: 4563

You can inject the Child Component using decorator @ViewChild():

@ViewChild(btn-icon)
private btnIcon: btn-icon;

Then you can access its properties like always:

this.btnIcon.childFunction();

Upvotes: 1

Eduardo Junior
Eduardo Junior

Reputation: 350

You should use @ViewChild in the parent component:

export class parentComponent implements OnInit {
   @ViewChild(BtnIcon)    btnIcon;
   
   parentFunction(){
     btnIcon.childFunction();
   }

the btnIcon property will only be available and filled with the child component after the ngAfterViewInit() lifecycle hook.

Attention: I used the class name BtnIcon in camelcase and not as "btn-icon" as your example.

Upvotes: 0

Eliseo
Eliseo

Reputation: 57919

just use ViewChild to get the children

export class parentComponent implements OnInit {

@ViewChild(btn-icon) bt-icon //see that viewChild argument is 
                             //the classname of your child-component
  parentFunction(){
     this.bt-icon.childFunction('inputValue');
  }
}

You can also use a template reference and pass as argument to a function, e.g.

    <div class="box">
        <!--see how, in input event you pass the template reference "child" futhermore
                  $event.target.value-->
        <input type="text" (input)="change(child,$event.target.value)"
                 placeholder={{placeHolder}} />
        
      <!--see the "#child", it's a template reference-->
      <btn-icon #child [searchType]='searchType' [searchText]='searchValue'></btn-icon> 
    </div>
change(childComponent:bt-icon,value){
    chilComponent.childFunction(value)
}

Upvotes: 2

Related Questions