0

I have an Angular Component with an Output. When I emit an event to this output, an async function will be called (this function is outside of the component).

Inside the component, I'd like to know when this outside function has finished. Is there any way to do that?

Here's some of the code of my component:

@Output() action: EventEmitter<string>;

itemClicked(item) {
    this.action.emit();
    // When the function of the observer is done: this.hideMenu();
}

And here's the code outside of the component:

<my-component (action)="getData()"></my-component>


getData() : Promise<any> {
    ...
}

Is there any way to detect that the "getData" function has finished inside of the component?

In AngularJS I could do it like this:

scope: {
    action: '&'
}
...

    scope.itemClicked = function(item) {
        $q.when(item.action()).finally(function() {
            scope.hideMenu();
        });
    };

EDIT:

I was thinking in another solution inspired by Ionic's refresher. What if the emit() call passes the instance of my component as a parameter? That way the getData function could do something like:

getData(menu): Promise<any> { 
    ...
    menu.hideMenu();
}

What do you think about this solution? If you think it's wrong then I guess I'll go with the Input.

PX Developer
  • 8,065
  • 7
  • 42
  • 66

3 Answers3

5

I think you should use an @Input to send the completed message when the function is done and in the interested component listen for the input with the set and do what you want knowing that the function is completed.

Fabio Carpinato
  • 1,121
  • 6
  • 13
2

AngularJS & binding was incorrectly translated to Angular. The proper counterpart is Input:

@Input() actionCallback: () => Promise<any>;

itemClicked(item) {
    this.actionCallback().then(...);
}

Which is used like:

<my-component [actionCallback]="getData">

While Output provides one-way interaction that isn't supposed to feed back. getData should be aware of its responsibilities and provide the feedback, through a callback or RxJS subject:

@Output() action: EventEmitter<Function>;

itemClicked(item) {
    this.action.emit(this.onClick);
}

onClick = () => {
  this.hideMenu();
}

Which is used like:

<my-component (action)="getData($event)"></my-component>

getData(callback) : Promise<any> {
    ...
    .then(callback);
}
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • I've used the callback approach, your "second" solution, and it works for me. Maybe the @Input solution is better in terms of architecture, but this one is more simple so I chose it. Thanks! – PX Developer Dec 21 '17 at 12:44
0

You can use the Host property to get the parent like so

@Output() action: EventEmitter<string>;

constructor(@Host() private parent: ParentComponent) {
    parent.getData().subscribe(...);
}

EDIT Type your parent as an abstract class

constructor(@Host() private parent: ConcernedParent) {
    parent.getData().subscribe(...);
}

export abstract class ConcernedParent {
  public abstract getData(): Observable<any>;
}
  • 1
    that would tightly couple the child component to its parent though, not truly reusable – Jota.Toledo Dec 21 '17 at 11:14
  • As Jota.Toledo said, I want this component to be used in several places of my app, so this solution isn't suitable for me :) – PX Developer Dec 21 '17 at 11:14
  • Anyways, if you want to re-use it, use this solution, and instead of typing your parent with a component, type with with an Interface/mother class, that has to implement a `getData` function. I mean, sure, you want to re-use it, but you still have to comply to something, and the least you can comply to is a function name –  Dec 21 '17 at 11:19
  • BTW, this will invoke the getData method on component instantiation, but OP wants to call that method only on event emit. So this doesnt really fulfill that. If getData is an observable that will emit when the data fetching is complete or not, you are basically defining an input property as already explained in the other answer. – Jota.Toledo Dec 21 '17 at 11:35
  • Like a madman of course. I followed OP's signature, but I should have went with my take on it. Edited my answer. And you can declare getData as a Subject if you want to have it on emit. I answered the OP on the basis he asked, and he forgot to mention key factors. So yeah, I'm not making a complete answer here, bear with me same as I bear with him ! –  Dec 21 '17 at 11:37