How to return a value from an EventEmitter function?

Angular

Angular Problem Overview


I got this function in my core component:

 isValid(value: any) {

   // Do some stuff and return something based on the result

   return false;
 }

Which I pass to the other-component like this:

<other-component (onBeforeAdding)="isValid($event)"></other-component>

And in other-component I got this EventEmitter function which should run before other things and return a value stating that a value is valid or not:

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

 let isValid = this.onBeforeAdding.emit(value) || true;

 if (isValid) {

   // Do stuff
 }
 

The problem here is that an EventEmitter function can't return a value since it's asynchronous (although from rc2 it seems that this is optional by passing true to the new EventEmitter function? Even doing so won't fix this issue however). So isValid will always be true regardless of what the function returns.

How can I return a value from the EventEmitter function?

Angular Solutions


Solution 1 - Angular

The short answer is you can't do this with @Output, but you can do something very similar with @Input.

Same function in core component:

isValid(value: any): boolean {
  // Do some stuff and return something based on the result
  return false;
}

Pass the function definition in to other-component as an @Input:

<other-component [onBeforeAddingProcessor]="isValid"></other-component>

In other-component:

@Input() onBeforeAddingProcessor: (value: any) => boolean;

ngOnInit() {
  // onBeforeAddingProcessor won't be defined in the constructor
  let isValid = this.onBeforeAddingProcessor(value);

  if (isValid) {
    // Do stuff
  }
}

Methods accessing this

If you have to access this in the function you provide, then it's necessary to pass a method which already has the this-context bound:

isValid = (value: any) => {
  return this.myService.checkValue(value);
}

Otherwise Angular calls the method with this of the component, not the consumer of the component. Small hint regarding performance (though not tested): if this method is large and the instance-count of the component is high, then you should factor out the bigger parts of the code to a private member function and call this function from where it was factored out. Reason: Above does not create a function on the prototype of the class, but stamps out a copy of this function for each instance of the component. This can consume a lot of memory which can be avoided easily.

Solution 2 - Angular

You need to subscribe on the event emitter to get the value:

this.onBeforeAdding.emit(value || true);

this.onBeforeAdding.subscribe(isValid => {
  if (isValid) {
    // Do stuff
  }
});

Solution 3 - Angular

This is possible without much effort

  1. Create EventEmitter within your child component
@Output('request_data')
requestData: EventEmitter<any> = new EventEmitter<any>();
  1. create a method to request data within your child component, the trick here is to pass an object with an anonymous function
    click() {
        this.requestData.emit({
            data: "some-data",
            func: (data_from_parent => {
               //do whatever you want
            })
        });
    }
  1. From your parent component, do whatever you want and call the function
     callFromChild(obj) {
        //obj.data
        //obj.func();
    }

Solution 4 - Angular

// Child
this.yourFunction.emit({func:(data_form_parent)=>{console.log(data_form_parent)}})

//Parent
yourFunction($event) {
 const {func}= $event;
 func('this data will return to your child')
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionChrillewoodzView Question on Stackoverflow
Solution 1 - AngularIsaacView Answer on Stackoverflow
Solution 2 - AngularThierry TemplierView Answer on Stackoverflow
Solution 3 - Angularimal hasaranga pereraView Answer on Stackoverflow
Solution 4 - AngularLenin GonzalezView Answer on Stackoverflow