Chris Barr
Chris Barr

Reputation: 33992

Angular 5 Component input function that takes parameters

In an Angular 2+ component, how do I pass in a callback function that takes parameters? My initial assumption was something like

<app-example [onComplete]="doThing('someParam')"></app-example>

And sometimes I won't need any parameters, like this:

<app-example [onComplete]="doSomeThingElse()"></app-example>

And then in the component I have

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  @Input() public onComplete: () => void;

  //run `this.onComplete()` somewhere as needed
}

But, what ends up happening is that the doThing('someParam') or doSomeThingElse() is immediately called without any interaction.

How am I supposed to pass callback functions in to a component to be called later?


EDIT:

The actual problem I am trying to solve here is to be able to run any passed in function at a later time. This is for a confirmation component that will ask the user "are you sure you want to continue?" and then if they press the "Yes I'm sure" button, the passed in function will run.

Upvotes: 19

Views: 70733

Answers (4)

Yhan
Yhan

Reputation: 76

The said solution will work only if you have a method that needs to invoke without taking action on the component itself. However, in my case, I need to execute an observable method inside of the app-example component and wait for the response to do some action inside of that component.

If anyone has the same issue. Here is the solution for it.

  1. create an interface.

    export interface Delegate<T> {
      (...args: any[]): T;
    }
    
  2. On your angular component, create a @Input variable

    @Component({
        selector: 'app-example',
        templateUrl: './example.component.html',
    })
    export class AppExampleComponent {
      @Input() executeWhen: Delegate<Observable<any>>;
    
      runOnComplete(): void {
        this.executeWhen().subscribe(() => // do some action);
      }
    }
    

Upvotes: 4

tlt
tlt

Reputation: 15211

Template:

<app-example [someParams]="someParamsObject"
             (complete)="onComplete($event)" >
</app-example>

Component:

@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  @Input()
  someParams: YourParamsType;

  @Output()
  complete:EventEmitter<any> = new EventEmitter<any>();

  //run `this.complete(this.someParams)` somewhere as needed and 
  //pack in some params if you need
}

In your calling, parent component you need a function named onComplete that receives parameter of type any in this case (that comes from @Output being defined as EventEmitter<any>). If you need, you can also have event parameters of any particular type you like EventEmitter<YourParticularType>.

Upvotes: 4

user8745435
user8745435

Reputation:

Here's an example of the @Output syntax @toskv was looking for, Angular pass callback function to child component as @Input

So for your example,

<app-example 
  (onComplete)="doThing()" 
  [completedParam]="'someParam'"></app-example>
@Component({
  selector: 'app-example',
  templateUrl: './example.component.html',
})
export class ExampleComponent {
  @Output() public onComplete: EventEmitter<any> = new EventEmitter();
  @Input() completedParam;

  runOnComplete(): void {
    this.onComplete.emit(this.completedParam);
  }
}

Does not feel as good as [onComplete]="doThing.bind(this, 'someParam')".

Upvotes: 26

Sagi
Sagi

Reputation: 8011

You can have a private method in your component:

private doThingFactory(param) {
  return () => this.doThing(param);
}

and then use it like that:

<app-example [onComplete]="doThingFactory('someParam')"></app-example>

Upvotes: 1

Related Questions