Error de tipo observable: no se puede leer la propiedad de undefined
Aplicación Angular 2, obtengo un error: no se puede leer la propiedad 'title' de undefined. Este es un componente muy simple, solo tratando de obtener un mínimo para trabajar aquí. Golpea mi controlador API (curiosamente varias veces), y parece golpear el área en mi código que es la devolución de llamada después de que se devuelve un objeto. Mi consola.log muestra 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 <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)
El servicio (about.Servicio.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();
});
}
}
El Componente (sobre.componente.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;
}
Índice.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>
3 answers
Por favor, incluya su vista y modelo la próxima vez (app/about/about.html y acerca de.modelo).
Si está devolviendo un array , puede usar el AsyncPipe , que "se suscribe a un Observable o Promise y devuelve el último valor que ha emitido. Cuando se emite un nuevo valor, la tubería asíncrona marca el componente a comprobar para los cambios" por lo tanto, la vista se actualizará con el nuevo valor.
Si devuelve un tipo primitivo (cadena, número, booleano) también puede usar el AsyncPipe.
Si devuelve un objeto , No tengo conocimiento de ninguna forma de usar AsyncPipe , podríamos usar la tubería async, en conjunto 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 mencionado en un comentario, puede subscribe()
al observable en el controlador y almacenar el objeto contenido en una propiedad de componente. A continuación, utilice el operador de navegación segura o ngIf en la plantilla:
Servicio.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);
}
}
Data/array.json
[ 1,2,3 ]
Data/primitive.json
Greetings SO friends!
Datos/objeto.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
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-25 09:10:14
Parece que se ha referido a about.title
en la vista about.html
pero la variable about
se crea una instancia solo después de que se complete la solicitud http
. Para evitar este error, puede envolver about.html
con <div *ngIf="about"> ... </div>
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-01-12 02:39:53
La respuesta anterior es correcta. Debe verificar si la variable está definida antes de usarla en su plantilla. Usando HTTP request necesita tiempo para definirlo. utilice * ngIf para comprobar. 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
<div *ngIf="hero">
<h2>{{hero.name}} details!</h2>
<div>
Puedes comprobar app/hero-detail.componente [ts y html]
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-27 15:31:53