组件初始化失败,NoProvider异常

时间:2016-08-17 12:12:27

标签: javascript angular

我正在开发一个使用Angular 2 RC4的应用程序(这里的关键字是RC4),我已经开发了一个我希望在需要的地方和时间使用的组件。

为此,我开发了这个简单的组件:

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;
    }
}

这是我的模板:

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

然后,我使用以下代码在另一个组件中调用此组件:

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")];
    (...)
}

在我的userDashboardComponent html上,我有以下内容:

<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>

但是,每当我运行此操作时,我在控制台中会遇到一堆关于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)

我在这里做错了什么?我已经浏览了文档,我看到的唯一区别是示例使用服务/提供程序来输入数据,我不想在这里,我希望能够直接初始化值

我已经在几周内搞乱了Angular2,所以这可能是一个新手问题,但我需要问其他SO线程没有提供答案。

有人可以帮忙吗?

2 个答案:

答案 0 :(得分:1)

您的组件BbTile的属性称为title,而不是tile! 而且你必须绑定每个值并且不能放入整个对象。

像这样使用:

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

如果你想像你的方式一样使用它(我假设) 你需要改变它..

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() { }
}

模板:

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

数组将是这样的:

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

最后你的ngFor:

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

刚刚在这里写下来,所以不要复制和粘贴准备好了,但你应该明白它背后的想法! :)

答案 1 :(得分:1)

您获得的具体错误是由于构造函数。构造函数需要两个字符串输入。创建组件实例时,它将由Angular在幕后创建。如果Angular发现构造函数需要参数,它将查看提供者列表以查找匹配的Provider以生成要注入构造函数的数据。在您的情况下,您没有可生成字符串的可注入提供程序,因此您会收到错误。

您在这里遇到的更重要的问题是设计问题。您尝试使用相同的对象(BbTile)作为用于存储值(tiles: BbTile[] = [new BbTile("Celso", "300"), new BbTile("ZéTó", "400")];)的数据保持对象和Angular用于显示值的可视组件。你不应该这样做。对于数据存储需求,您最终需要一个带有字符串参数的构造函数,而对于组件,您需要一个空构造函数(数据通过@Input()带注释的属性进入)。还有一个事实是你携带一个组件的额外行李与你的数据存储(当你认为BbTile的一个实例是你使用新的BbTile(...)创建时,可能会出现混乱),不会是这种情况。)

相反,使用不同对象(或字符串)的数组来存储UsersDashboardComponent中的tile [],可能是这样的:

tiles: any[] = [{"title": "Celso", "value": "300"}, {"title":"ZéTó", "value":"400"}]

然后使用HTML参数将值传递给BbTile(它连接到BbTile Angular实例上的@Input属性):

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

你的BbTile将保持大致相同,但是会有一个空的构造函数:

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

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

  constructor() { }
}