Zed_Blade Zed_Blade - 3 months ago 19
Javascript Question

Component Initialization failing with NoProvider exception

I'm developing an application with Angular 2 RC4 (keyword here is RC4) and I've developed a component which I want to use where and whenever needed.

To do so, I've developed this simple component:

import { Component, Input, OnInit, OnDestroy } from '@angular/core';
import { Panel } from 'primeng/primeng';

@Component({
selector: "bb-tile",
templateUrl: "app/shared/tile/index.html",
directives: [Panel]
})

export class BbTile{
@Input() title: string;
@Input() value: string;

constructor(title: string, value: string) {
this.title = title;
this.value = value;
}
}


And this is my template:

<p-panel class="boxesdashboard">
<header>
{{title}}
</header>
{{value}}
</p-panel>


Then, I call this component inside another component by using this code:

import { Component } from '@angular/core';
import { HTTP_PROVIDERS } from '@angular/http';
(...)
import { BbTile } from "./../../../shared/tile/tile.component";

@Component({
templateUrl: 'app/pages/users/dashboard/index.html',
selector: 'my-app',
// Honestly I'm not sure if all of these are required here
directives: [InputText, DataTable, Button, Dialog, Column, Header, Footer, Panel, ProgressBar, Dropdown,
SplitButton, SplitButtonItem, Toolbar, SelectButton, OverlayPanel, Checkbox, ToggleButton, BbTile],
providers: [HTTP_PROVIDERS, UsersService]


})

export class UsersDashboardComponent {
// Data variables
user: User = new PrimeUser();
selectedUser: User;
newUser: boolean;
users: User[] = [];

tiles: BbTile[] = [new BbTile("Celso", "300"), new BbTile("ZéTó", "400")];
(...)
}


And on my userDashboardComponent html, I have the following:

<h1 class="ui-g-12 titlebox">Users Dashboard</h1>
<div class="ui-g-6 tiles-flex-wrap">
<bb-tile *ngFor="let t of tiles" [tile]="tile"></bb-tile>
</div>
</h1>


However, whenever I run this I get a bunch of errors in my console regarding NoProviderExceptions:


browser_adapter.ts:82 EXCEPTION: Error in app/pages/users/dashboard/index.html:20:3BrowserDomAdapter.logError @ browser_adapter.ts:82BrowserDomAdapter.logGroup @ browser_adapter.ts:93ExceptionHandler.call @ exception_handler.ts:58(anonymous function) @ application_ref.ts:374schedulerFn @ async.ts:148SafeSubscriber.__tryOrUnsub @ Subscriber.ts:240SafeSubscriber.next @ Subscriber.ts:192Subscriber._next @ Subscriber.ts:133Subscriber.next @ Subscriber.ts:93Subject._finalNext @ Subject.ts:154Subject._next @ Subject.ts:144Subject.next @ Subject.ts:90EventEmitter.emit @ async.ts:133onError @ ng_zone.ts:142onHandleError @ ng_zone_impl.ts:95ZoneDelegate.handleError @ zone.js:336Zone.runTask @ zone.js:268drainMicroTaskQueue @ zone.js:491ZoneTask.invoke @ zone.js:435
browser_adapter.ts:82 ORIGINAL EXCEPTION: No provider for String!BrowserDomAdapter.logError @ browser_adapter.ts:82ExceptionHandler.call @ exception_handler.ts:70(anonymous function) @ application_ref.ts:374schedulerFn @ async.ts:148SafeSubscriber.__tryOrUnsub @ Subscriber.ts:240SafeSubscriber.next @ Subscriber.ts:192Subscriber._next @ Subscriber.ts:133Subscriber.next @ Subscriber.ts:93Subject._finalNext @ Subject.ts:154Subject._next @ Subject.ts:144Subject.next @ Subject.ts:90EventEmitter.emit @ async.ts:133onError @ ng_zone.ts:142onHandleError @ ng_zone_impl.ts:95ZoneDelegate.handleError @ zone.js:336Zone.runTask @ zone.js:268drainMicroTaskQueue @ zone.js:491ZoneTask.invoke @ zone.js:435
browser_adapter.ts:82 ORIGINAL STACKTRACE:BrowserDomAdapter.logError @ browser_adapter.ts:82ExceptionHandler.call @ exception_handler.ts:74(anonymous function) @ application_ref.ts:374schedulerFn @ async.ts:148SafeSubscriber.__tryOrUnsub @ Subscriber.ts:240SafeSubscriber.next @ Subscriber.ts:192Subscriber._next @ Subscriber.ts:133Subscriber.next @ Subscriber.ts:93Subject._finalNext @ Subject.ts:154Subject._next @ Subject.ts:144Subject.next @ Subject.ts:90EventEmitter.emit @ async.ts:133onError @ ng_zone.ts:142onHandleError @ ng_zone_impl.ts:95ZoneDelegate.handleError @ zone.js:336Zone.runTask @ zone.js:268drainMicroTaskQueue @ zone.js:491ZoneTask.invoke @ zone.js:435
browser_adapter.ts:82 Error: DI Exception
at NoProviderError.BaseException [as constructor] (exceptions.ts:21)
at NoProviderError.AbstractProviderError [as constructor] (reflective_exceptions.ts:59)
at new NoProviderError (reflective_exceptions.ts:92)
at ReflectiveInjector_._throwOrNull (reflective_injector.ts:849)
at ReflectiveInjector_._getByKeyDefault (reflective_injector.ts:878)
at ReflectiveInjector_._getByKey (reflective_injector.ts:840)
at ReflectiveInjector_.get (reflective_injector.ts:633)
at ElementInjector.get (element_injector.ts:23)
at ElementInjector.get (element_injector.ts:23)
at ReflectiveInjector_._getByKeyDefault (reflective_injector.ts:876)


What am I doing wrong here? I've been over the docs and the only difference I see is that the examples use a Service/Provider to input data, where I don't really want that here, I want to be able to intialize the values directly.

I've been messing with Angular2 for a couple of weeks now, so this might be a newbie question, but I need to ask as other SO threads didn't provide an answer.

Can anyone help please?

Answer

The property of your Component BbTile is called title and not tile !! And you have to bind each value and cant just put in the whole object.

Use it like this:

<bb-tile *ngFor="let t of tiles" [title]="t.title" [value]="t.value"></bb-tile>

If you want to use it like your way (that i assumed) .. You need to change it a bit..

export class BbTileModel {
   public title: string;
   public value: string;

   constructor (... init stuff here ...) { ... }
}

@Component({
    selector: "bb-tile",
    templateUrl: "app/shared/tile/index.html",
    directives: [Panel]
})

export class BbTile {
    @Input() tile: BbTileModel;

    constructor() { }
}

The Template:

<p-panel class="boxesdashboard">
    <header>
        {{tile.title}}
    </header>
        {{tile.value}}
</p-panel>

the array would be like this:

tiles: BbTileModel[] = [new BbTileModel("Celso", "300"), new BbTileModel("ZéTó", "400")];

and finally your ngFor:

<bb-tile *ngFor="let t of tiles" [tile]="t"></bb-tile>

Just wrote it down here, so its not copy and paste ready, but you should get the idea behind it! :)