1
votes

I have pretty much the same question as in ngrx get value in function , but I'm wondering if the answer (see comment in that topic) is still the best practice nowadays.

My situation is:

  1. I want to get 2 values from the store to show in my component --> I use a selector and the async pipe
  2. I need to pass those same values to an Angular Material dialog, to work with them in the dialogcomponent.

I have a working solution: I use subscribe functions in ngOnInit() and set a local variable with the value from the Observable. So I don't need to use the async pipe anymore and I can easily pass the value to some functions... This one sounds like the best option, but everywhere I look for answers I see "avoid using subscriptions".

So I'm wondering:

  • is there a better way of handling this scenario?
  • Or is this "the ngrx/rxjs way of handling this scenario"?
  • Or do I use the selector Observable and async pipe to show the value in the component AND subscribe to the Observable to create a local variable to pass to my function (this seems a bit redundant...)
  • Or ...?

My problem is that I want a consistent approach of handling ngrx values, but now it looks like I need to use 2 approaches depending on the scenario:

  • Async pipe for showing values in component (preferred approach according to the community)
  • Subscription when using values in local functions (community advises against the use of subscriptions "unless necessary")

(To my surprise: it's hard to find a clear answer on the internet ...)

1

1 Answers

2
votes

Right, you need to avoid subscriptions. Use async pipe with as, ideally you'll have 0 subscriptions in your code.

In the component class we create a stream that selects data from store

export class MyComponent implements OnDestroy {
    public readonly data$: Observable<{
        user: User,
        items: Array<Item>,
    }>;

    constructor(protected readonly store: Store<StoreState>) {
        this.data$ = combineLatest([
            this.store.select(currentUser),
            this.store.select(someItems),
        ]).pipe(
            map(([user, items]) => ({
                user,
                items,
            })),
        );
    }

    public submit(user: User, item: Item): void {
        // some logic here
    }
}

and then in its template we have a wrapper that resolves it.

<ng-container *ngIf="data$ | async as data">
    <div>header</div>
    <button *ngFor="let item of data.items" (click)="submit(data.user, item)">{{data.user.name}} {{item.name}}</button>
    <div>footer</div>
</ng-container>