3
votes

First of all thanks for your time.

I am new to Angular 2 and I am trying to understand how to solve this problem I have.

Component Structure:

<parent-component>
  <dynamic-button></dynamic-button>
  <dynamic-button></dynamic-button>
  ...
</parent-component>

Child component

export class DynamicButtonComponent {
  @Output() clicked: EventEmitter<any> = new EventEmitter<any>();

  loading: Boolean = false;
  handleClick(event: any) {
    this.loading = true;
    this.clicked.emit(event);
  }
};

When I click on the Dynamic button I am sending an event to the parent. A spinner will be shown next to the button using 'loading' variable. Parent then makes an API call, when the API call is done I would like to send a prop back to the Child component from the parent (which initially send the event) to stop showing the spinner.

Please advise what would be the best/cleanest way to solve this. I thought of having a callback to the event emitter but I read in StackOverflow that it is against Angular 2's principle

1
What about an @Input property bound to a parent's object that will be updated in your api's callback? angular.io/docs/ts/latest/cookbook/… - elvin
You typically use a service to share state between components. Here's a code outline for implementing a spinner service like you described: stackoverflow.com/a/42041945 - AngularChef
@AngularFrance Thanks for your reply first of all. In my scenario, every button can have a spinner component, would they be all subscribing to the same service? - Bobin Varghese
Hmm. In that case, you'd have to structure the code differently. I'd still use a service, but instead of just emitting start/stop events, I would also pass some id to identify which button to start/stop. The problems with using input/output for parent-child communication are 1) it's a lot of boilerplate code for each button; 2) you might end up in a scenario where the button is not always an immediate child of the parent doing the action. Using a service lets you get around these limitations. - AngularChef

1 Answers

6
votes

You can use the OnChanges lifecycle hook to catch an @Input update on the child component to progress.

Parent:

export class ParentComponent {
    finishedLoading: boolean = false;
    doApiWork(){
        ...
        finishedLoading = true;
    }
}

Child:

export class DynamicButtonComponent implements OnChanges{
    @Input() loadingDone = false;

    ngOnChanges(){
        if(loadingDone){
           //Execute 
        }
    }
}

Bind in view:

<parent-component>
  <dynamic-button [loadingDone]="finishedLoading"></dynamic-button>
  ...
</parent-component>