Search code examples
angulartypescriptobservablengrx

Angular container @input property of observable


I'm not sure how to approach my question exactly, But What I'm trying to solve is how to extract a property from an observable for use as an @input. I am concerned think my approach is fundamentally flawed but lets imagine this scenario. What I'm doing is using the following object (PlanContext), which is effectively a wrapper class, as the input into my container that derives a few different bits of metadata.

PlanContext {
     Plan: Plan;

     //Other fields

}

Ok, so we've got the planContext, I'm handling the store and/or service call in a reducer so as to handle lockups based on different endpoints.

export class EditPlanPageComponent extends BaseComponent implements OnInit {
      public planContext$: Observable<PlanContext>;
      public planContext: PlanContext;
      public plan$: Observable<Plan>; ???
      public plan: Plan;              ????

      ngOnInit() {
        this.planContext$ = this.route.snapshot.data["planContext"];
        this.planContext$.subscribe(pc => {
           this.planContext = pc;

        });
        //this.plan/this.plan$  = ????? Pipe?
      } 
} 

The HTML I have is something like this:

<div class="fixed-top">
  <plan-nav [plan]="????" </plan-nav>
  <read-costsummary-page [plan]="????"> </read-costsummary-page>
  <read-plancontextsummary-page [(planContext)]="planContext"> </read-plancontextsummary-page>     
</div>

However, it seems like any of the references to plan don't work right. I've tried numerous approaches. Is there an approach to this general concept I should be taking? By that I mean: If I have an observable object, and I want to have a component only use a property of it and show changes, how should this be structured?


Solution

  • You can use pluck operator to focus on a property of your data stream. you can find more details here

    In your case, you can transform your code like below:

    export class EditPlanPageComponent extends BaseComponent implements OnInit {
          public planContext$: Observable<PlanContext>;
          public plan$: Observable<Plan>; ???
    
          ngOnInit() {
            this.planContext$ = this.route.snapshot.data["planContext"];
            this.plan$ = this.planContext$.pipe(pluck('Plan'));
          } 
    } 
    
    

    and in you html template you use the pipe async like below

    <div class="fixed-top">
      <plan-nav [plan]="plan$ | async"> </plan-nav>
      <read-costsummary-page [plan]="plan$ | async"> </read-costsummary-page>
      <read-plancontextsummary-page [(planContext)]="planContext$ | async"> </read-plancontextsummary-page>     
    </div>