0

I have a Template like this

Component.html

    <h1>aditya</h1>
    <div class="row">
    <div class="col-xs-12 col-sm-12 col-md-12 col-lg-12">
      <table class="table table-bordered">
        <thead>
          <tr>
            <th style="white-space: nowrap" *ngFor="let columns of data?.display_columns; let i = index">{{columns}}</th>
          </tr>
          <tr *ngFor="let row1 of data?.row1; let i= index">
            <td style="white-space: nowrap" *ngFor="let columns of data?.display_columns; let i = index">{{row1[columns]}}</td>
          </tr>
        </thead>
      </table>
    </div>
  </div>  

Component.ts

import { Component, OnInit } from '@angular/core';
import { HttpModule } from '@angular/http';
import { SpreadsheetService } from '../dataservice/spreadsheet.service';

@Component({
    moduleId: module.id,
    selector: 'sd-list-view',
    templateUrl: 'list-view.component.html',
    styleUrls: ['list-view.component.css'],
    providers: [HttpModule, ListService]

})

export class ListViewComponent implements OnInit {
    data: any;
    spreadsheet: any;
    data1: any;
    isDataAvailable: boolean = false;
    constructor(public _spreadsheetService: SpreadsheetService) {
    }
ngOnInit() {
    this._spreadsheetService.getData()
        .subscribe(data => {
            this.data = data;
            (<any>window)['mydata'] = (data);
            console.log(this.data.display_columns);
            var data1: any;
            //alert('get data');
            return this.data;
        });
    //alert('list view 2');
    }
}

The first line of the template "Aditya" is getting displayed but the data table inside the loop is not loading on the Component Initialization.

How can I run the loop and load the data before the View is initialized or another case be to load the Table data after the View is initialized?
PS: The loop is tested and working. I don't want to use APP_Initializer.
I have gone through this question but could not understand the solution as I am using Observables instead of Promise. Thanks in Advance.

Aditya Shukla
  • 316
  • 1
  • 3
  • 20
  • What part of the linked question did you not understand? – Günter Zöchbauer Oct 27 '17 at 10:51
  • @GünterZöchbauer I could not understand this line of your answer where you are waiting for promise to load first - "ngOnInit() { this.fetchEvent().then(() => console.log(this.ev)); // Now has value; }" If I have to do the same thing, i.e., wait for Observable to load and return the data first before the template is rendered, how would one do it in my case? – Aditya Shukla Oct 27 '17 at 11:10
  • just use `subscribe()` instead of `then()` – Günter Zöchbauer Oct 27 '17 at 11:24
  • How does your incoming data actually look like? – AT82 Oct 27 '17 at 19:06

2 Answers2

0

You can wrap the content of your template with

<ng-container *ngIf="data">
 template content here
</ng-container>

If you are using the router, you can use a resolver

and if you want the data to be loaded before even AppComponent is initialized, you can use How to pass parameters rendered from backend to angular2 bootstrap method

Günter Zöchbauer
  • 623,577
  • 216
  • 2,003
  • 1,567
0

Since your data is undefined it will be displaying some error like "Cannot read data undefined". Your view is initialized but since your request spreadsheetService.getData() is an async request it gives its response later.

You can either use a check variable:

public isLoaded=false;

And in subscriber of your getData() request make that boolean true:

 this._spreadsheetService.getData()
    .subscribe(data => {
        this.isLoaded=true;
        this.data = data;
    });
}

And in html:

<div *ngIf="isLoaded">
//Your content
</div>

Another approach through which you can avoid is check is simply declare your data as an empty array initially so that while it loops nothing gets printed at start.

  data: Array<any>=[];

If you want to get data loaded before view is initialized use resolvers. They resolve your service request and after response recieve they initialize the view.

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { MyService } from './my-service.ts';

@Injectable()
export class MyResolver implements Resolve<any> {

   constructor(private myservice: MyService) {}

  resolve(route: ActivatedRouteSnapshot) {
   return this.myservice.getData();
  }
}

Add this resolver in providers just like you do with service. And add that resolver to your route to something like:

{
    path: 'mypath', component: MyComponent,
    resolve: {
      myData: MyResolver
    }
  },
  • I am not getting any error. An undefined error I see when I don't use an Elvis (?) operator with the variable on ngFor loop Let me give it a shot to your answer. – Aditya Shukla Oct 27 '17 at 11:01
  • Then in that case if you want data before view initialization you can use resolvers. Giving you a sample code in above answer – Ali Raza Sherazi Oct 27 '17 at 11:04
  • Just tried this solution. Unfortunately, it is still the same. Data is getting called every time and I can see it in the log. But not rendering – Aditya Shukla Oct 27 '17 at 11:04
  • I've added the way to load data before initialization of view in above comment. Hoping it'll be helpful – Ali Raza Sherazi Oct 27 '17 at 11:09