Angular 模板中异步管道的Observable不适用于单个值

Angular 模板中异步管道的Observable不适用于单个值,angular,rxjs,rxjs5,Angular,Rxjs,Rxjs5,我有一个组件,它向我的服务请求一个可观察的对象(即,底层http.get返回一个对象) 在我的模板中,对象(可观察对象)与异步管道一起使用。 不幸的是,我得到了一个错误: Cannot read property 'lastname' of null 这件事让我伤了脑筋。类似类型的代码可以正确地处理对象列表(与*ngFor结合使用) {{(person | async)?.lastname} 我的服务中的方法: .... getPerson(id: string): Observab

我有一个组件,它向我的服务请求一个可观察的对象(即,底层http.get返回一个对象)

在我的模板中,对象(可观察对象)与异步管道一起使用。 不幸的是,我得到了一个错误:

Cannot read property 'lastname' of null
这件事让我伤了脑筋。类似类型的代码可以正确地处理对象列表(与*ngFor结合使用)

  • {{(person | async)?.lastname}
  • 我的服务中的方法:

      ....
      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
      }
      ....
    
    。。。。
    getPerson(id:string):可观察的{
    让url=this.personsUrl+“/”+id;
    返回这个.http.get(url,{headers:newheaders({'Accept':'application/json'})})
    .map(r=>r.json())
    .catch(this.handleError);//错误处理程序
    }
    ....
    
    在我的组件中:

    //... 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();
      }
    }
    
    /。。。未经批准的进口
    @组成部分({
    moduleId:module.id,
    选择器:“应用程序详细信息人员”,
    templateUrl:'details person.component.html',
    样式URL:['details-person.component.css'],
    })
    导出类DetailsPersonComponent实现OnInit、OnDestroy{
    人:可见;
    分:认购;
    构造函数(私有personService:personService,私有路由:ActivatedRoute){
    }
    恩戈尼尼特(){
    this.sub=this.route.params.subscribe(params=>{
    设persId=params['id'];
    this.person=this.personService.getPerson(perId);
    });
    }
    ngOnDestroy():void{
    此.sub.取消订阅();
    }
    }
    
    显然,observable是/返回管道中的空对象值。 我已经检查了我是否真的从我的服务中得到了一个非空的可观察对象,并且我可以确认存在一个从我的服务返回的(底层)对象

    当然,我可以在从服务中检索到可观察内容后,在组件中订阅可观察内容,但我确实希望使用异步构造


    顺便说一句,还有一个问题:是否已经有了一种模式来处理异步管道中发生的错误?(使用异步管道的一个缺点是…错误会延迟到视图的渲染时间。

    视图第一次渲染时,未定义
    person
    ,因为只有在触发路由参数订阅时才异步创建该组件属性。您需要先创建一个空的可观察对象,而不是

    person:Observable<Person>;
    
    人:可观察;
    
    试一试

    person=Observable.of(person());//或者创建一个空的person对象
    //空对象可能需要将lastname字段设置为“”或null
    

    我通常通过以下方式处理服务中的错误:

  • 返回一个空的可观察对象
  • 向某个应用程序范围(单例)服务报告错误。然后,某个(单例)组件会在页面的某个位置显示这些错误(如果合适)

  • 请换一下电话线

    person:Observable< Person>
    
    人:可观察的
    
    进入

    人:可观察的

    如果这不起作用,请打印出这个
    {{person | async | json}
    当然,请使用上面的更改,看看您得到了什么。

    您不需要订阅在
    ngOnInit
    中可观察到的路由数据

    您可以将路线数据和personService observable链接到一个新的observable中,而不是在每次路线数据observable发出时订阅并创建一个全新的observable。这是函数式编程的本质:

    函数式反应式编程的本质是指定 值在声明时的动态行为

    记住这一点,您可以在声明时声明关于“人”的所有信息:

    person: Observable<Person> = this.route.params.pipe(
      map(params => params.id),
      mergeMap(persId => this.personService.getPerson(persId)),
    );
    

    如果使用可观察的
    主题,而不是
    回放主题
    行为主题
    ,则可能发生这种情况

    主题发生的情况是,它只向当时注册的任何侦听器“广播”一次其值

    因此,如果您在可观察的
    消息中调用
    next('hello word')
    :Subject
    ,它只能在该时刻存在该UI“片段”时更新UI

    因此,在本例中,消息不会出现-除非您调用
    next
    两次

    <div *ngIf="message | async">
       here is the message {{ message | async }}
    </div>
    
    
    这是消息{{message | async}}
    

    最简单的解决方案是使用
    ReplaySubject(1)
    ,其中
    1
    是它记住的值的数量(我们这里只需要一个).

    这应该可以。请显示您返回可观察的服务代码,以及您定义
    人员的组件代码。或者更好,创建一个。Hi Mark,我已经更新了上面的问题部分。您可以阅读上面的服务片段和组件代码。谢谢。Hi Mark,谢谢您的回复。确实,我同意as关于person和route params代码的同步行为。我遵循了您的建议,但我仍然看到相同的错误。似乎在定义person(使用服务调用)之前呈现了视图。我是否处于错误的生命周期?如果
    person=Observable.of(person());是在构造函数之前定义的,它应该在第一次呈现视图时存在。您可以通过注释您的
    this.person=…`code来测试这一点。Hi Mark,在(之前)这样做了,但没有成功。这是一个脑残:-(我开始思考我是否对库和兼容性有问题。正如你之前所说的……这应该是可行的。直截了当,但仍然是一个问题。你是否尝试了flatMap而不是map?这应该是公认的答案。它避免创建空的person对象,在有正确方法时用作解决方法,并避免出现unnec随笔订阅。
    person:Observable< any>;
    
    person: Observable<Person> = this.route.params.pipe(
      map(params => params.id),
      mergeMap(persId => this.personService.getPerson(persId)),
    );
    
     <li *ngIf="(person | async) as person">{{person.lastname}}</li>
    
    <div *ngIf="message | async">
       here is the message {{ message | async }}
    </div>