Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 / Ionic2 :: Reload component

Tags:

angular

ionic2

I have a component on my root page that exposes a few bindable properties and can be used like this:

<myprogress [value]="current" [max]="maximum"></myprogress>

In my application, various types objects require progress display. So I created some directives like below:

@Directive({
  selector: 'myprogress[order]'
})
export class OrderProgress {
  @Input('order') order: Order;
  constructor(private baseComponent: Progress) {}
  ngOnInit() {
    this.baseComponent.value = this.order.currentStage;
    this.baseComponent.max   = this.order.totalStages;
  }
}

This allows me to replace calls like:

<myprogress [value]="order.currentStage" [max]="order.totalStages"></myprogress>

with a more readable:

<myprogress [order]="order"></myprogress>

This works fine until some part of the application changes the order itself. In that case, myprogress components which have already been rendered, are not updated. And I can see why too. The ngOnInit function runs just once when the component is rendered and there is no way to indicate to the directive that some property of the order has changed and new values for value and max need to be calculated.

Is there a way to solve this problem?

One possible solution I have is this:

  1. Modify Progress component to accept numbers as well as a function that returns a number.
  2. In OrderProgress's ngOnInit, bind as follows: this.baseComponent.value = () => this.order.currentStage

But it requires me to change Progress component as well. Is there a way which doesn't require me to change Progress or Order?

like image 688
AweSIM Avatar asked Apr 03 '26 03:04

AweSIM


2 Answers

It sounds like you need to implement an observable over the order object. If you're sharing that object across multiple components and need to have those components be made aware of changes to the order object, it's best to create an Observable. We use the BehavoirSubject class from rxjs to do just that.

RxJs BehaviorSubject

Here is and example of how you can create the BehavoirSubject:

export class TokenService {

    public tokenSubject: BehaviorSubject<OpenIdToken> = new BehaviorSubject<OpenIdToken>(<OpenIdToken>{});

OpenIdToken is a custom typescript class that i want to share across my app.

Here is how you notifiy subscribers of a change to the underlying object:

setObservableToken(token: OpenIdToken): void {
        if (token) {
            this.tokenSubject.next(token);
        }
    }

after .next is called the new token object value will propigate to all subscribers. Here is how you subscribe to the BehaviorSubject:

export class PatientComponent implements OnInit, OnDestroy {    

    patient: Patient;

    constructor(private _tokenService: TokenService, private _patientService: PatientService) { }

    ngOnInit() {
        this._tokenService.tokenSubject.subscribe(token => {
            if (token && token.access_token && token.access_token.length>0) {
                this._patientService.getPatient(token)
                    .subscribe(_patient => this.patient = _patient);
            }
        });
    }

subscribe is a delegate that will execute when the subscription broadcasts a change to the token( when it calls .next(token)). In this case when i get an OpenIdToken I want to fetch the patient using the token so I call another service.

like image 103
cobolstinks Avatar answered Apr 08 '26 07:04

cobolstinks


The order type must be a Subject or BehaviorSubject so when you update the order the template of myprogress should update as well. You will need to use the async pipe to subscribe to the observable.

<myprogress [order]="order$ | async"></myprogress>

Check this code. You will need to call this.newOrder({...}); to update the order.

@Component({
  selector: 'page-home',
  template: `
    <ion-header>
      <ion-navbar>
        <ion-title>Home</ion-title>
      </ion-navbar>
    </ion-header>

    <ion-content padding>
       <myprogress [order]="order$ | async"></myprogress> 
    </ion-content>
 `
})
export class HomePage implements OnInit,OnDestroy{

  order$: Subject<any> = new Subject();

  constructor(public navCtrl: NavController){
  }

  ngOnInit(){
  }

  newOrder(order : any){
    this.order$.next(order);
  }

  ngOnDestroy(){
    this.order$.unsubscribe();
  }

}
like image 32
Victor Godoy Avatar answered Apr 08 '26 05:04

Victor Godoy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!