0

I am having an issue with some html not loading when the component is loaded until the data being recieved from the api call via the service.

Here is the relevant code:

import { ApiService } from './services/api.service';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent implements OnInit, OnDestroy {

  thedata;

  subscription: Subscription;

  constructor(private apiService: ApiService) {}

  ngOnInit() {
    this.getData();
  }

  ngOnDestroy() {
    this.subscription.unsubscribe();
  }


  getData() {
    this.apiService.getUsers().subscribe(
      (res) => {
        this.thedata = [res];
      },
      (err) => {
        console.log('There was an error: ' + err);
      }
    )
  }

}

Then in the html file:

<div *ngFor="let data of thedata">
   <!-- other elements here and below -->
    {{ data.name }}
</div>

My problem is that although there are visual element to render it is not rendering until the data is loaded.

Is there a way to render the html whiles the data is still being loaded from the api ?

4
  • this may be root of your problem ngOnInit() { this.getData(); } if you want to render empty component maybe move it to ngAfterViewInit Commented Jul 11, 2019 at 14:30
  • I've tried adding this.getData() inside the ngAfterViewInit() {} but the html is still not loading with the rest of the app...there's still a big delay Commented Jul 11, 2019 at 14:37
  • alternative slution would be to use service worker did you tried build your app for production it should have build in service worker module ServiceWorkerModule.register('ngsw-worker.js'), that should at least make your UI responsive Commented Jul 11, 2019 at 14:43
  • So you want to iterate an array that in your code is only defined after the HTTP request is completed. Why dont you simply define a starting value for it? Commented Jul 11, 2019 at 14:49

4 Answers 4

2

The reason why it's not working, is cause there isn't any data when initializing your component.

You could reduce it all into just this. The async pipe will take care of subscribing/unsubscribing part. On top of that, it will wait for the data to be loaded and then passes the data to the for loop.

component:

import { ApiService } from './services/api.service';

export interface ExpectedDataModel {
  name: string;
}

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {

  myData: Observable<ExpectedDataModel[]>;

  constructor(private apiService: ApiService) {
    this.myData = this.apiService.getUsers(); // I suppose this returns an array of objects ///
  }
}

template:

<div *ngFor="let data of myData | async">
   <!-- other elements here and below -->
    {{ data.name }}
</div>
Sign up to request clarification or add additional context in comments.

Comments

0

As long as thedata is empty your *ngFor will not be run, so everything inside that div will not be added to the DOM. You would have to place the content to be rendered while your data is loading outside the *ngFor.

Comments

0

No you cant, the *ngFor directive mark the elements (and it children) as the "repeater template", the template create repeated time match with the amount of items in your array. So the "repeater template" will never exist in DOM as long as the length of your input array is 0.

You can try to mock the array value with dummy items in your ts while it waiting for the API response like:

thedata = [1,2,3,4,5,6]

Comments

0

Try:-

.ts

 getData() {
const self = this;   //<====== add this
    this.apiService.getUsers().subscribe(
      (res) => {
      console.log(JSON.stringify(res)); <======
        self.thedata = [res];    
      },
      (err) => {
        console.log('There was an error: ' + err);
      }
)

}

.html

<ng-container *ngIf="thedata">
<div *ngFor="let data of thedata">
   <!-- other elements here and below -->
    {{ data?.name }}
</div>
</ng-container>

1 Comment

I don't that would be the problem, since the OP using arrow function in their snippet

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.