我有一个组件,它向我的服务请求一个Observable对象(也就是说,底层的http.get返回一个单独的对象)。
对象(可观察对象)与模板中的异步管道一起使用。 不幸的是我收到了一个错误:
Cannot read property 'lastname' of null
我一直在打破这个问题。类似的代码类型在对象列表上正确工作(与* ngFor一起使用)。
<li>{{(person | async)?.lastname}}</li>
我服务中的方法:
....
getPerson(id: string): Observable<Person> {
let url = this.personsUrl + "/" + id;
return this.http.get(url, {headers: new Headers({'Accept':'application/json'})})
.map(r => r.json())
.catch(this.handleError); //error handler
}
....
在我的组件中:
//... imports ommitted
@Component({
moduleId: module.id,
selector: 'app-details-person',
templateUrl: 'details-person.component.html',
styleUrls: ['details-person.component.css'],
})
export class DetailsPersonComponent implements OnInit, OnDestroy {
person: Observable<Person>;
sub: Subscription;
constructor(private personService: PersonService, private route: ActivatedRoute) {
}
ngOnInit() {
this.sub = this.route.params.subscribe(params => {
let persId = params['id'];
this.person = this.personService.getPerson(persId);
});
}
ngOnDestroy(): void {
this.sub.unsubscribe();
}
}
显然,observable是/在管道中返回一个空对象值。 我已经检查过我是否真的从我的服务中获得了一个非空的Observable,我可以确认我的服务中存在一个(底层)对象。
当然,我可以在从服务中检索Observable后订阅我的组件中的observable,但我真的想使用异步构造。
顺便问一下,其他问题:是否已有一种模式如何处理异步管道中发生的错误? (使用异步管道的缺点......错误会延迟到视图的渲染时间。
答案 0 :(得分:4)
视图第一次呈现时,person
未定义,因为只有当params订阅触发时,才会异步创建该组件属性。您需要最初创建一个空的observable。而不是
person:Observable<Person>;
试
person = Observable.of<Person>(Person()); // or however you create an empty person object
// the empty object probably needs a lastname field set to '' or null
我通常通过
处理服务中的错误答案 1 :(得分:2)
请尝试更改
行person:Observable< Person>
到
person:Observable< any>;
如果这不起作用,请打印此{{ person | async | json }}
,当然请更改上面的内容,看看你得到了什么。
答案 2 :(得分:1)
如果您使用Subject<T>
而不是ReplaySubject<T>
或BehaviorSubject<T>
的话,就会发生这种情况。
Subject<T>
发生的事情是,它一次仅向当时注册的所有听众“广播”其值。
因此,如果您在可观察的next('hello word')
上调用message: Subject<string>
,则只有在该“ UI”当时存在时,它才能更新UI。
因此,在此示例中,消息不会出现-除非您两次致电next
!
<div *ngIf="message | async">
here is the message {{ message | async }}
</div>
最简单的解决方案是使用ReplaySubject<string>(1)
,其中1
是它记住的值的数量(我们在这里只需要一个)。
答案 3 :(得分:0)
您无需订阅ngOnInit
中可观察到的路线数据。
您不必每次发送可观察路线数据时都订阅和创建全新的可观察路线,而是可以将路线数据与personService可观察路线链接在一起,形成一个新的可观察路线。这是函数式编程的本质:
函数式反应式编程的本质是指定 一个值在声明时完全是动态的。
请记住,您可以在声明时声明有关“人”的所有内容:
person: Observable<Person> = this.route.params.pipe(
map(params => params.id),
mergeMap(persId => this.personService.getPerson(persId)),
);
这有很多好处:
话虽如此,异步管道仍可以默认为null,您可以在模板中使用ngIf
对其进行处理:
<li *ngIf="(person | async) as person">{{person.lastname}}</li>