Error de tipo observable: no se puede leer la propiedad de indefinido

Aplicación angular 2, obtengo un error: no puedo leer la propiedad ‘título’ de indefinido. Este es un componente muy simple, solo intenta obtener el mínimo indispensable para trabajar aquí. Golpeó mi controlador API (curiosamente varias veces), y parece golpear el área en mi código que es la callback después de que se devuelve un objeto. Mi console.log genera el objeto que esperaría. Aquí está el error completo:

TypeError: Cannot read property 'title' of undefined at AbstractChangeDetector.ChangeDetector_About_0.detectChangesInRecordsInternal (eval at  (http://localhost:55707/lib/angular2/bundles/angular2.dev.js:10897:14), :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) 

El servicio (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 res.json(); }); } } 

El componente (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

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

Incluya su vista y modelo la próxima vez (app / about / about.html y about.model).

Si está devolviendo una matriz , puede usar asyncPipe , que “se suscribe a un Observable o promesa y devuelve el último valor que ha emitido. Cuando se emite un nuevo valor, la tubería asíncrona marca el componente que se comprobará para ver los cambios” la vista se actualizará con el nuevo valor.

Si devuelve un tipo primitivo (cadena, número, booleano), también puede usar asyncPipe.

Si devuelve un objeto , no conozco ninguna forma de utilizar asyncPipe , podríamos utilizar el tubo asincrónico, junto con el operador de navegación segura ?. como sigue:

 {{(objectData$ | async)?.name}} 

Pero eso parece un poco complicado, y tendríamos que repetir eso para cada propiedad de objeto que queríamos mostrar.

Como @pixelbits se menciona en un comentario, puede subscribe() a lo observable en el controlador y almacenar el objeto contenido en una propiedad del componente. Luego use el operador de navegación segura o NgIf en la plantilla:

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

aplicaciones

 @Component({ selector: 'my-app', template: ` 
array data using '| async':
{{item}}
primitive data using '| async': {{primitiveData$ | async}}
object data using .?: {{objectData?.name}}
object data using NgIf: {{objectData.name}}
` 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); } }

data / array.json

 [ 1,2,3 ] 

data / primitive.json

 Greetings SO friends! 

data / object.json

 { "name": "Mark" } 

Salida:

 array data using '| async': 1 2 3 primitive data using '| async': Greetings SO friends! object data using .?: Mark object data using NgIf: Mark 

Plunker

Parece que se ha referido a about.title en la vista about.html pero la variable about se instancia solo después de que se complete la solicitud http . Para evitar este error, puede envolver about.html con

...

La respuesta anterior es correcta. Debe verificar si la variable está definida antes de usarla en su plantilla. Al usar la solicitud HTTP, necesita tiempo para definirla. use * ngIf para verificar. El ejemplo se proporciona desde angular con https://angular.io/docs/ts/latest/tutorial/toh-pt5.html y el ejemplo es http://plnkr.co/edit/?p=preview

 

{{hero.name}} details!

Puede verificar la aplicación / hero-detail.component [ts y html]