Observabletypes错误:无法读取undefined的属性
Angular 2应用程序,我得到一个错误:不能读取未定义的属性“标题”。 这是一个非常简单的组件,只是为了获得最低限度的工作。 它命中我的API控制器(好奇地多次),它似乎击中了我的代码中返回对象后的callback区域。 我的console.log输出我期望的对象。 这是完整的错误:
TypeError: Cannot read property 'title' of undefined at AbstractChangeDetector.ChangeDetector_About_0.detectChangesInRecordsInternal (eval at <anonymous> (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:10897:14), <anonymous>:31:26) at AbstractChangeDetector.detectChangesInRecords (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8824:14) at AbstractChangeDetector.runDetectChanges (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8807:12) at AbstractChangeDetector._detectChangesInViewChildren (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8877:14) at AbstractChangeDetector.runDetectChanges (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8811:12) at AbstractChangeDetector._detectChangesContentChildren (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8871:14) at AbstractChangeDetector.runDetectChanges (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8808:12) at AbstractChangeDetector._detectChangesInViewChildren (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8877:14) at AbstractChangeDetector.runDetectChanges (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8811:12) at AbstractChangeDetector.detectChanges (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:8796:12)
服务(about.service.ts):
import {Http} from 'angular2/http'; import {Injectable} from 'angular2/core'; import {AboutModel} from './about.model'; import 'rxjs/add/operator/map'; @Injectable() export class AboutService { constructor(private _http: Http) { } get() { return this._http.get('/api/about').map(res => { console.log(res.json()); // I get the error on the line above but this code is still hit. return <AboutModel>res.json(); }); } }
组件(about.component.ts):
import {Component, View, OnInit} from 'angular2/core'; import {AboutModel} from './about.model'; import {AboutService} from './about.service'; import {HTTP_PROVIDERS} from 'angular2/http'; @Component({ selector: 'about', providers: [HTTP_PROVIDERS, AboutService], templateUrl: 'app/about/about.html' }) export class About implements IAboutViewModel, OnInit { public about: AboutModel; constructor(private _aboutService: AboutService) {} ngOnInit() { this._aboutService.get().subscribe((data: AboutModel) => { this.about = data; }); } } export interface IAboutViewModel { about: AboutModel; }
的index.html
<script src="~/lib/systemjs/dist/system.src.js"></script> <script src="~/lib/angular2/bundles/router.js"></script> <script src="~/lib/angular2/bundles/http.js"></script> <script src="~/lib/angular2/bundles/angular2-polyfills.js"></script> <script src="~/lib/angular2/bundles/angular2.dev.js"></script> <script src="~/lib/es6-shim/es6-shim.js"></script> <script> System.config({ packages: { app: { format: 'register', defaultExtension: 'js' }, rxjs: { defaultExtension: 'js' } }, map: { rxjs: "lib/rxjs" } }); System.import('app/boot') .then(null, console.error.bind(console)); </script>
请在下次包含您的视图和模型(app / about / about.html和about.model)。
如果你正在返回一个数组 ,你可以使用asyncpipe ,它“订阅一个Observable或Promise并返回它发出的最新值。当一个新的值被发出时,asynchronouspipe道标记要检查的组件被修改”该视图将更新为新的值。
如果你正在返回一个原始types (string,数字,布尔),你也可以使用asyncPipe。
如果你正在返回一个对象 , 我不知道有什么方法来使用asyncpipe ,我们可以使用asynchronouspipe道,结合安全的导航操作符 ?.
如下:
{{(objectData$ | async)?.name}}
但是看起来有点复杂,我们不得不重复一遍我们想要显示的每个对象属性。
作为注释中提到的@pixelbits,您可以subscribe()
到控制器中的observable,并将包含的对象存储到组件属性中。 然后在模板中使用安全导航运算符或NgIf:
service.ts
import {Injectable} from 'angular2/core'; import {Http} from 'angular2/http'; import 'rxjs/add/operator/map'; // we need to import this now @Injectable() export class MyService { constructor(private _http:Http) {} getArrayData() { return this._http.get('./data/array.json') .map(data => data.json()); } getPrimitiveData() { return this._http.get('./data/primitive.txt') .map(data => data.text()); // note .text() here } getObjectData() { return this._http.get('./data/object.json') .map(data => data.json()); } }
app.ts
@Component({ selector: 'my-app', template: ` <div>array data using '| async': <div *ngFor="let item of arrayData$ | async">{{item}}</div> </div> <div>primitive data using '| async': {{primitiveData$ | async}}</div> <div>object data using .?: {{objectData?.name}}</div> <div *ngIf="objectData">object data using NgIf: {{objectData.name}}</div>` providers: [HTTP_PROVIDERS, MyService] }) export class AppComponent { constructor(private _myService:MyService) {} ngOnInit() { this.arrayData$ = this._myService.getArrayData(); this.primitiveData$ = this._myService.getPrimitiveData(); this._myService.getObjectData() .subscribe(data => this.objectData = data); } }
数据/ array.json
[ 1,2,3 ]
数据/ primitive.json
Greetings SO friends!
数据/ object.json
{ "name": "Mark" }
输出:
array data using '| async': 1 2 3 primitive data using '| async': Greetings SO friends! object data using .?: Mark object data using NgIf: Mark
Plunker
看起来你已经在about.html
的视图中引用了about.title
,但只有在http
请求完成之后, about
variables才会被实例化。 为了避免这个错误,你可以用<div *ngIf="about"> ... </div>
来包装about.html
以前的答案是正确的。 在模板中使用之前,您需要检查variables是否已定义。 使用HTTP请求需要时间来定义它。 使用* ngIf来检查。 示例从https://angular.io/docs/ts/latest/tutorial/toh-pt5.html的angular度提供,示例是http://plnkr.co/edit/?p=preview
<div *ngIf="hero"> <h2>{{hero.name}} details!</h2> <div>
你可以检查app / hero-detail.component [ts和html]