Force a function to return value for property binding after async data is loaded

1.4k views Asked by At
<cv-radio-button-group class="duration-radios" 
    [radioItems]="getRadioButtons()" 
</cv-radio-button-group>

So i have this angular 2 component <cv-radio-button-group> which is a custom made radio button group. The amount of radio buttons is determined by the property [radioItems]. This all works very will in a sync environment.

But now i'm implementing it in the project with calls to the server and now it's in an async environment. So at startup the getRadionButtons() function is called, this while the call to the server is still doing its thing. And getRadiobuttons() needs data from the server to return the correct amount of radio buttons, so i'm not getting the correct result.

I can force it by clicking somewhere else and clicking back, forcing ngOnInit() to run.

Is there a way to force the function to return it again when the async data is finished?

2

There are 2 answers

3
Z. Bagley On BEST ANSWER

There are at least 3 different approaches you can take from this, but it sounds like you're looking for a full DOM approach, which is possible with use of *ngIf.

For your button group you can actually make a logic statement with your function to check the state of the return before rendering, note that <ng-container> doesn't actually produce and DOM:

<ng-container *ngIf="getRadioButtons() && getRadioButtons().length>
  <cv-radio-button-group class="duration-radios" 
    [radioItems]="getRadioButtons()" 
   </cv-radio-button-group>
</ng-container>

In the above code the logic state is expecting first getRadioButtons() to return an item, and (assuming it's return will be an array) it then makes sure that the array is populated before rendering.

As mentioned in the comments, normally this type of check is best implemented in you typescript component and/or service with use of Observables (or a Promise). The Angular: Tour of Heroes - Http covers this well, and in depth.

Example of promise:

const promise =
  new Promise((resolve, reject) => {
  // do some async stuff

  if (CONDITION) resolve(DATA);
  else reject(ERROR);
  })
  .then(
  (data) => { console.log(data); },
  (err) => { console.log(err); }
  );

For your example in your component typescript component.ts you would add typescript like this:

radioData: any;
isLoaded: false;

getRadioButtons {
  const promise = new Promise((res, rej) => {
    // ... previous radioButtons code ... ends with data.
    res(radioButtonsData) // this sends the data to the promise handlers below
  })
  .then((data) => { this.radioData = data; this.isLoaded = true; })

And you would either use an *ngIf="isLoaded" or you can instead simply use an async pipe.

For an excellent detailed use example of promises and more advanced level use check out this link and go to the section "Write your first promise".

0
Amit Chigadani On

Why don't you call getRadioButtons() in ngOnInit() and then assign the results to [radioItems].

Assuming that getRadioButtons() will return Observable.

public radioCount;

ngOnInit() {
       this.getRadioButtons().subscribe(
          (data) => {
            this.radioCount = data;
      });
}

.html

<div *ngIf="radioCount">
   <cv-radio-button-group class="duration-radios" 
        [radioItems]="radioCount" 
   </cv-radio-button-group>
</div>