Datatable: not rendering until event

UI Components for Angular
Post Reply
tme321
Posts: 4
Joined: 22 Mar 2016, 20:42

22 Mar 2016, 21:42

I will start by saying that I am not 100% sure this is even a primeNG issue, but this problem is only manifesting itself when I am using primeNG components so I figured it was worth a post here.

This problem exists when using typescript 1.8, ng2 beta 10, and both primeNG 0.7 and 0.8.2.

The problem I am experiencing seems to have something to do with the zones that ng2 uses. Each of my components have a constructor and ngOnInit defined. Both are called automatically when the page with the component is loaded.

However, when the link is clicked that routes to the datatabledemo component the behaviour is different. First the constructor is called normally. But ngOnInit is not called autoomatically, therefore the table is never rendered.

After messing around with it for quite a while I added a button in to the datatabledemo template, and when the button click event is fired then, and only then, is ngOnInit called.

The problem seems to be something with the zones the app is executing in. Any component that does not use primeNG components fires off both the constructor and ngOnInit in the zone called 'root'. However, while the datatabledemo constructor runs in the zone 'root' I have noticed (through the commented out alerts), that when the button is clicked and an event is fired the ngOnInit function finally executes, but it does so in zone 'angular'.

After some exhaustive googling I have found this solution:
http://stackoverflow.com/questions/3569 ... h-angular2

Where if in the constructor of datatabledemo I call the cars service with an explicit call to zone.run the data is retrieved properly and immediately rendered:

Code: Select all

this.zone.run(() => this.carService.getCarsSmall().then(cars => this.cars = cars));
However, so far this is the only solution I have come up with. If I call the carService directly, without zone.run, in the constructor I still get the same behaviour of the datatable not rendering until the button is clicked.

This solution is not ideal, because this code should really be inside ngOnInit. And it also does not explain *why* ngOnInit is not being called automatically.

One more thing to note: once the button is clicked I am getting the table rendered exactly as expected. I am also not getting any errors, 404 or otherwise, in the console during execution. So I am confident that all of my resources are being found properly and everything like that. I do not think it is an issue with the way I have the code set up or anything.

As I mentioned, this might not even be a primeNG issue, but it only manifests itself when using prime components.

Any help you can provide would be appreciated.

The base html:

Code: Select all

<h3>
    Angular 2 Examples
</h3>

<!-- load angular 2 components -->
<script src="lib/es6-shim/es6-shim.min.js"></script>
<script src="lib/angular2/ts/src/testing/shims_for_IE.js"></script>
<script src="lib/angular2/bundles/angular2-polyfills.js"></script>
<script src="lib/systemjs/dist/system-polyfills.js"></script>
<script src="lib/systemjs/dist/system.js"></script>
<script src="lib/rxjs/bundles/rx.js"></script>
<script src="lib/angular2/bundles/angular2.dev.js"></script>
<script src="lib/angular2/bundles/router.dev.js"></script>
<script src="lib/angular2/bundles/http.dev.js"></script>

<!-- load PrimeUI components -->
<script src="lib/primeui/primeui-ng-all.min.js"></script>

<!-- configure SystemJS -->
<script>
        System.config({
            packages: {
                app: {
                    defaultExtension : 'js'
                },
                services: {
                    defaultExtension: 'js'
                },
                models: {
                    defaultExtension: 'js'
                },
                components: {
                    defaultExtension: 'js'
                },
                interfaces: {
                    defaultExtension: 'js'
                },
                primeng: {
                    defaultExtension: 'js'
                },
                examples: {
                    defaultExtension: 'js'
                },
                primengEx: {
                    defaultExtension: 'js'
                },
                datatable: {
                    defaultExtension: 'js'
                },
                demo: {
                    defaultExtension: 'js'
                }
            },
            map: {
                'primeng': 'lib/primeng'
            }
        });
        System.import('./app/examples/boot')
            .then(null, console.error.bind(console));
</script>
A standard boot script:

boot.ts

Code: Select all

///<reference path="../../lib/zone.js/dist/zone.js.d.ts"/>
///<reference path="../../lib/angular2/typings/browser.d.ts"/>

import {bootstrap} from 'angular2/platform/browser';
import {provide} from 'angular2/core';
import {HTTP_PROVIDERS} from 'angular2/http';
import {Ng2ExamplesComponent} from './ng2examplesComponent';
import {ROUTER_PROVIDERS, LocationStrategy, HashLocationStrategy} from 'angular2/router';
import 'rxjs/Rx';

bootstrap(Ng2ExamplesComponent, [ROUTER_PROVIDERS, provide(LocationStrategy, { useClass: HashLocationStrategy })]);
boot loads my Ng2ExamplesComponent:

Code: Select all

import {Component, Inject, Directive, ViewChild, Output, OnInit} from 'angular2/core';
import {RouteConfig, ROUTER_DIRECTIVES} from 'angular2/router';
import {DataTableDemoComponent} from './datatable/demo/datatable/datatabledemo';

@Component({
    selector: 'angular2-examples',
    templateUrl: 'app/examples/ng2ExamplesTemplate.html',
    directives: [ROUTER_DIRECTIVES]
})
@RouteConfig([
        { path: '/datatabledemo', name: 'DataTableDemo', component: DataTableDemoComponent}
])
export class Ng2ExamplesComponent implements OnInit {
    Text: string; // = "Angular 2 example success!";

    constructor() {
        //alert("Ng2 Ex constr zone: " + Zone.current.name);
    }

    ngOnInit() {
        //alert("Ng2 Ex init zone: " + Zone.current.name);
        this.Text = "Angular 2 example success!";
    }
}
The template is simple (note that the binding to Text here works as expected):

Code: Select all

<base href="NG2Examples/">
<div>
    {{Text}}
</div>
<span>Demos</span>
<div>
    <a class="SubMenuLink" [routerLink]="['DataTableDemo']" >Data Table Demo</a>
</div>
<div>
    <router-outlet></router-outlet>
</div>
The datatabledemo script is pretty much a copy and paste from the github repo with import paths changed as necessary:

Code: Select all

import {Component, OnInit, NgZone, Inject} from 'angular2/core';
import {HTTP_PROVIDERS}    from 'angular2/http';
import {ROUTER_DIRECTIVES} from 'angular2/router';
import {DataTable} from '../../../../../lib/primeng/components/datatable/datatable';
import {Car} from '../domain/car';
import {Column} from '../../../../../lib/primeng/components/column/column';
import {CarService} from '../service/carservice';

@Component({
    templateUrl: '/app/examples/datatable/demo/datatable/datatabledemo.html',
    directives: [DataTable, Column, ROUTER_DIRECTIVES],
    providers: [HTTP_PROVIDERS, CarService, CarModel]
})
export class DataTableDemoComponent implements OnInit {
    message: string = "Force Bindings";
    cars: Array<Carl>;
    cols: any[];

    constructor( private carService : CarService, private zone: NgZone) {
        //this.zone.run(() => this.carService.getCarsSmall().then(cars => this.cars = cars));
    }

    ngOnInit() {
        this.carService.getCarsSmall().then(cars => this.cars = cars);
        //alert("Dtd.ts ngInit zone: " + Zone.current.name);
        this.cols = [
            { field: 'vin', header: 'Vin' },
            { field: 'year', header: 'Year' },
            { field: 'brand', header: 'Brand' },
            { field: 'color', header: 'Color' }
        ];
    }

    onClickDemo() {
        var x = 0;
        x++;
    }
}
The template is a simplified copy and paste from github. Note that here is the problem, ngOnInit from the component does not execute until the button is clicked. When I tried this example without the button nothing was ever being rendered:

Code: Select all

<div>
    <button (click)="onClickDemo()">Something</button>
    <div>{{message}}</div>
    <h3>Basic</h3>

    <p-dataTable [value]="cars">
        <p-column field="vin" header="Vin"></p-column>
        <p-column field="year" header="Year"></p-column>
        <p-column field="brand" header="Brand"></p-column>
        <p-column field="color" header="Color"></p-column>
    </p-dataTable>

    <h3>Dynamic Columns</h3>
    <p-dataTable [value]="cars">
        <p-column *ngFor="#col of cols" [field]="col.field" [header]="col.header"></p-column>
    </p-dataTable>
</div>
for reference car.ts (again straight from github):

Code: Select all

export interface Car {
    vin;
    year;
    brand;
    color;
}
carservice:

Code: Select all

import {Injectable, Inject} from 'angular2/core';
import {Http, Response} from 'angular2/http';
import {Car} from '../domain/car';

@Injectable()
export class CarService {
    http: Http;

    constructor( @Inject(Http) http) {
        this.http = http;
    }

    getCarsSmall() {
        alert("Car srv zone: " + Zone.current.name);
        return this.http.get('../app/examples/datatable/resources/data/cars-small.json')
            .toPromise()
            .then(res => <Car[]>res.json().data)
            .then(data => { return data; });
    }

    getCarsMedium() {
        return this.http.get('showcase/resources/data/cars-medium.json')
            .toPromise()
            .then(res => <Car[]>res.json().data)
            .then(data => { return data; });
    }

    getCarsLarge() {
        return this.http.get('showcase/resources/data/cars-large.json')
            .toPromise()
            .then(res => <Car[]>res.json().data)
            .then(data => { return data; });
    }
}
and cars-small.json:

Code: Select all

{
  "data": [
    {
      "brand": "VW",
      "year": 2012,
      "color": "White",
      "vin": "dsad231ff"
    },
    {
      "brand": "Audi",
      "year": 2011,
      "color": "Black",
      "vin": "gwregre345"
    },
    {
      "brand": "Renault",
      "year": 2005,
      "color": "Gray",
      "vin": "h354htr"
    },
    {
      "brand": "BMW",
      "year": 2003,
      "color": "Blue",
      "vin": "j6w54qgh"
    },
    {
      "brand": "Mercedes",
      "year": 1995,
      "color": "White",
      "vin": "hrtwy34"
    },
    {
      "brand": "Volvo",
      "year": 2005,
      "color": "Black",
      "vin": "jejtyj"
    },
    {
      "brand": "Honda",
      "year": 2012,
      "color": "Yellow",
      "vin": "g43gr"
    },
    {
      "brand": "Jaguar",
      "year": 2013,
      "color": "White",
      "vin": "greg34"
    },
    {
      "brand": "Ford",
      "year": 2000,
      "color": "Black",
      "vin": "h54hw5"
    },
    {
      "brand": "Fiat",
      "year": 2013,
      "color": "Red",
      "vin": "245t2s"
    }
  ]
}

cagatay.civici
Prime
Posts: 18616
Joined: 05 Jan 2009, 00:21
Location: Cybertron
Contact:

22 Mar 2016, 21:49

Zones have some issues on beta10 and beta11, can you please try with beta9?

CC84
Posts: 69
Joined: 11 Mar 2016, 09:32

22 Mar 2016, 21:54

ng2 Beta 10 and 11 seem to be broken.

I just got back to Beta 8 (my last stable version, skipped 9 and 10), cause 11 was unusable.

http://stackoverflow.com/questions/3613 ... f-undefine

I think currenlty it's waste of time to investigate this problem. Just wait for Beta 12 or use an version prior 10.

cagatay.civici
Prime
Posts: 18616
Joined: 05 Jan 2009, 00:21
Location: Cybertron
Contact:

22 Mar 2016, 21:59

Yes, we are also still on beta9 due to these issues.

tme321
Posts: 4
Joined: 22 Mar 2016, 20:42

22 Mar 2016, 22:41

I would gladly use beta9 but the entire reason Im using beta10 is whenever I try to use primeNG with beta9 I get NPM dependency errors:

npm ERR! peerinvalid The package es6-shim@0.35.0 does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer angular2@2.0.0-beta.9 wants es6-shim@^0.33.3
npm ERR! peerinvalid Peer primeng@0.8.2 wants es6-shim@^0.35.0


So, Ill change es6-shim to ^0.33.3 and...

npm ERR! peerinvalid The package es6-shim@0.33.3 does not satisfy its siblings' peerDependencies requirements!
npm ERR! peerinvalid Peer angular2@2.0.0-beta.9 wants es6-shim@^0.33.3
npm ERR! peerinvalid Peer primeng@0.8.2 wants es6-shim@^0.35.0

How do you resolve this issue with beta9 and primeng?

Thanks.

cagatay.civici
Prime
Posts: 18616
Joined: 05 Jan 2009, 00:21
Location: Cybertron
Contact:

22 Mar 2016, 23:01

With 0.33, I keep getting unexpected token < errors, 0.35 fixes that, I had no problem using 0.35 with beta9. Dependency settings that work well are

Code: Select all

  "dependencies": {
    "angular2": "2.0.0-beta.9",
    "systemjs": "0.19.24",
    "es6-promise": "^3.0.2",
    "es6-shim": "^0.35.0",
    "reflect-metadata": "0.1.2",
    "rxjs": "5.0.0-beta.2",
    "zone.js": "0.5.15",
    "primeng": "0.8.2",
    "primeui": "4.1.5"
  },

tme321
Posts: 4
Joined: 22 Mar 2016, 20:42

23 Mar 2016, 00:10

Ok, I resolved all the dependency issues, and got it working so that I'm using the dependencies you listed.

And that seemed to fix half the issue. I can now just call carService.GetSmallCars directly, without any zone.run stuff, and it executes and renders the datatable correctly. However, ngOnInit is still not automatically executing when datatabledemo is navigated to. If I put the call to carService.GetSmallCars into the constructor the data is fetched and the datatable is rendered. However, until I cause an event, like with a button click, ngOnInit is never executing in the datatabledemo. Once it does execute the carService fetches the data and the table is rendered. So it really seems like the issue is just with ngOnInit not automatically being called here.

I'm not sure how this is a primeNG thing, but again, this isn't happening in any component where I don't use primeNG. In my other components ngOnInit is automatically called after the constructor.

Thanks for all your help so far, any further ideas?

cagatay.civici
Prime
Posts: 18616
Joined: 05 Jan 2009, 00:21
Location: Cybertron
Contact:

23 Mar 2016, 00:30

Just to be clear, so your ngOnInit() as in below does not get called right? Here is the code from datatable demo to load the data initially. In your case, it does not get called?

https://github.com/primefaces/primeng/b ... bledemo.ts

tme321
Posts: 4
Joined: 22 Mar 2016, 20:42

23 Mar 2016, 00:57

Yes that was the problem. However, I discovered the solution. Hopefully if this happens to anyone else they will find this answer and not go through what I have gone through. Short version is I had the initial <src> includes in a slightly different order. Apparently order is VERY important with these.

http://stackoverflow.com/questions/3462 ... 6#35058096

The correct order is:

<script src="lib/es6-shim/es6-shim.min.js"></script>
<script src="lib/systemjs/dist/system-polyfills.js"></script>
<script src="lib/angular2/bundles/angular2-polyfills.js"></script>
<script src="lib/systemjs/dist/system.js"></script>

Any other order can cause VERY odd issues for angular 2 apps.

Sorry for the trouble, thanks for all the help.

cagatay.civici
Prime
Posts: 18616
Joined: 05 Jan 2009, 00:21
Location: Cybertron
Contact:

23 Mar 2016, 12:49

Glad to hear mystery is resolved, thanks for sharing. I'm sure it will be useful for future reference.

Post Reply

Return to “PrimeNG”

  • Information
  • Who is online

    Users browsing this forum: No registered users and 23 guests