8

I'm trying to create a component with a cancel and send buttons to avoid c&p on each form but I can't find a way to pass functions as a parameter to the component selector

HTML:

<btn-submit [cancelFunction]='test' [acceptFunction]='test'></btn-submit>

TS Parent:

test = () => console.log("this is a test");

TS Child:

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

@Component({
  selector: 'btn-submit',
  styleUrls: ['./btn.component.scss'],
  template: `
          <button class="btn" click="cancelFunction()">
              <fa name="times"></fa>
          </button>
          <button class="btn" click="acceptFunction()">
              <fa name="check"></fa>
          </button>
  `
})

export class BtnSubmitComponent {
  @Input() cancelFunction: any;
  @Input() acceptFunction: any;
}
2
  • You should be using Output instead really Commented Jul 26, 2018 at 19:45
  • You are using event binding when I think you need to be using property binding. If you want to pass the functions in to the nested child component, you need the Input decorator, but need to bind it using property binding. Also, I think you want to pass in the function, not execute the function, so you may need to take the () off. Commented Jul 26, 2018 at 19:47

3 Answers 3

10

If you want to actually pass a function in from a parent component to a child component you can do it as shown in the code below.

But using the more common @Output and EventEmitter approach as shown in other answers may be a better option. The @Output technique does not let you pass in a function, but does allow your parent component to receive events from the child component that you can respond to by calling a function in the parent component.

Here is code that allows you to pass a function in from a parent component to a child component.

Parent component

test = () => console.log("this is a test");

Parent template

<pm-star [rating]='product.starRating'
    [testFunction]='test'
    (ratingClicked)='onRatingClicked($event)'>
</pm-star>

Notice the square brackets (property binding) and it does not call a function but rather binds to a property of the component containing the function.

Child component

  @Input() testFunction: any;

Child template

<div class="crop"
     [style.width.px]="starWidth"
     [title]="rating"
     (click)="testFunction()">

I have a stackblitz with a simple working example here: https://stackblitz.com/edit/angular-jwguwk?file=src%2Fapp%2Fapp.component.ts

Sign up to request clarification or add additional context in comments.

4 Comments

Do you know why it doesn't work now? I've just edited the OP. Tried C&P the code from stackblitz and it works correctly but mine doesn't
These need to use event binding: (click)="cancelFunction()" You are missing the parenthesis in your code.
Thanks for the help, that was the main issue of my code since I did all the tests without binding click. I also tried with @user184994 example and it didn't work because of that
Thanks! works perfectly, and exactly what I looked for.
7

You can use the @Output decorator in conjunction with EventEmitter class to achieve this

Child component (Typescript and markup)

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

        @Component({
          selector: 'btn-submit',
          styleUrls: ['./btn.component.scss'],
          template: `
                  <button class="btn" click="cancelFunction()">
                      <fa name="times"></fa>
                  </button>
                  <button class="btn" click="acceptFunction()">
                      <fa name="check"></fa>
                  </button>
          `
        })

        export class BtnSubmitComponent {
          @Output() clicked: EventEmitter<any> = new EventEmitter();
          cancelFunction(){
            this.clicked.emit("CANCELLED"); // Pass any payload as argument
          }
          acceptFunction{
            this.clicked.emit("ACCEPTED"); // Pass any payload as argument
          }
        }

Parent markup

<btn-submit (clicked)="onAddClicked($event)" [acceptFunction]='test'></btn-submit>

Parent Typescript function

onAddClicked(event: any){
console.log(event); // Your payload is in 'event'
}

Comments

0

Change it from @Input to @Output

@Output() acceptFunction = new EventEmitter<any>();

Then, inside your component when you want to invoke it, do:

this.acceptFunction.emit();

The HTML can stay as is.

    <btn-submit (cancelFunction)="myCancelFunction()"
            (sendFunction)="mySendFunction()></btn-submit>

Each time you call .emit(), it will fire an event. The parent will hear this event, and call which function you've bound (e.g. mySendFunction)

2 Comments

What's the advantage of using Output in this case?
@prevox That's already explained in the answer by Deborah. Quoting here - "But using the more common @Output and EventEmitter approach as shown in other answers may be a better option. The @Output technique does not let you pass in a function, but does allow your parent component to receive events from the child component that you can respond to by calling a function in the parent component."

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.