How to select part of a NGXS state?

944 views Asked by At

I'm reading and trying the documentation of NGXS: https://www.ngxs.io/concepts/select

Except I'm doing this for my AuthState.

I've already implemented the AuthStateModel and the AuthState:

import { AngularFireAuth } from '@angular/fire/auth';
import { AngularFirestore, AngularFirestoreDocument } from '@angular/fire/firestore';
import { Action, NgxsOnInit, Selector, State, StateContext } from '@ngxs/store';
import { profile } from 'console';
import { User } from 'firebase';
import { LoginWithPasswordAction, RegisterAction, SendLostPasswordAction, SignoutAction } from './auth.actions';
import { Profile } from './auth.model';
import { emailToGravatarUrl } from 'email-gravatar';
import { switchMap } from 'rxjs/operators';
import { Observable, of, Subscription } from 'rxjs';
import { Injectable, OnDestroy } from '@angular/core';

export interface AuthStateModel {
  profile: Profile | null;
  loaded: boolean;
}
@State<AuthStateModel>({
  name: 'auth',
  defaults: {
    profile: null,
    loaded: false,
  },
})
@Injectable()
export class AuthState implements NgxsOnInit, OnDestroy {
  private profileSubscription: Subscription;

  constructor(private angularFireAuth: AngularFireAuth, private angularFireStore: AngularFirestore) {}

  ngOnDestroy(): void {
    //some cleaning
  }

  ngxsOnInit(ctx?: StateContext<any>) {
    //Some init
  }

    /// Some actions...
}

but now in my app.component.ts, I'm struggling to select.

According to them, I should be able to do something like:

@Select(AuthState.profile.displayName) name$: Observable<string>;

But VS Code says(and for what I see, I agree) that there is no "profile" on AuthState, which is correct, because this property exists on the AuthModel.

I've seen the Memoized Selectors that comes after, but that's not really the point. Also I've tried to make one that return the Profile, and then use just AuthState.Profile.displayName, but same result on displayName.

What am I missing?

1

There are 1 answers

1
Garth Mason On

To select just the profile part of the state the simplest/easiest way would be to define a selector

@Selector()
static profile(state: AuthStateModel): Profile { 
 return state.profile;
}

Then you can use it in your component via the static reference in your example @Select(AuthState.profile)

Alternatively, you could @Select(state => state.profile.displayName) directly, or create an observable that projects what you need:

@Select(AuthState) authState$: Observable<AuthStateModel>;

displayName$: Observable<string>;

ngOnInit(): void { 

  this.displayName$ = this.authState$.pipe(
    filter(state => !!state.profile),
    map(state => state.profile.displayName),
  );
}