Anna Lee
Anna Lee

Reputation: 951

Can't use select in ngrx/store

I am testing state management features using ngrx/store like below. The very weird thing is I can't use select method in the user.selectors.ts. It says that Property 'select' does not exist on type 'Observable'. AppState is defined in the reducers.ts properly. To use 'select', import '@ngrx/core/add/operator/select' is added in the user.selectors.ts, also I confirmed that there is select.ts file in the properly located in the node_modules folder.

user.actions.ts

import { Injectable } from '@angular/core';
import { Action } from '@ngrx/store';

@Injectable()
export class UserActions {

  static LOGIN = 'LOGIN';
  static LOGOUT = 'LOGOUT';

  logIn (token: string) {
    return { type: UserActions.LOGIN, token };
  }

  logOut() : Action {
    return { type: UserActions.LOGOUT };
  }
}

user.reducers.ts

import '@ngrx/core/add/operator/select';
import { Observable } from 'rxjs/Observable';
import { Action } from '@ngrx/store';
import { UserActions } from './user.actions';

export * from './user.actions';

export interface User {
  access_token: string;
  is_authenticated: boolean;
};

const initialUserState: User = {
  access_token: '',
  is_authenticated: false
};

export function userReducer(state = initialUserState, action: Action): User {
  switch (action.type) {
    case UserActions.LOGIN:
      return Object.assign( {}, state, { access_token: action.payload })
    case UserActions.LOGOUT:
      return Object.assign( {}, state, { access_token:'' } )

    default:
    return state;
  }
};

user.selectors.ts

import { Observable } from 'rxjs/Observable';
import { UserProfile } from './user.reducers';
import { AppState } from '../reducers';
import '@ngrx/core/add/operator/select';

export function getUser$(state$: Observable<AppState>): Observable<User> {
  return state$.select(state => state.user.access_token);
}

Could you please help me out with this?

The way I build like below.

app - auth
    - core    - store
              - service
    - shared

Inside store directory, 5 files are resident, user.actions.ts, user.reducer.ts, user.selectors.ts, app-store.ts and index.ts.

I tried to make one module from store directory like following.

index.ts

import { Observable } from 'rxjs/Observable';
import { NgModule } from '@angular/core';
import { StoreModule, combineReducers } from '@ngrx/store';
import { compose } from '@ngrx/core';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import 'rxjs/add/operator/let';
import '@ngrx/core/add/operator/select';
import { UserActions } from './user-profile.actions';
import { userReducer } from './user-profile.reducer';
import { AppState } from './app-store';

@NgModule({
  imports: [
    StoreModule.provideStore({userReducer}),
  ],
  declarations: [],
  exports: [],
  providers: [UserActions]
})
export class CoreStoreModule {};

FYI, app-store.ts looks like below.

import { User } from './user.reducer';

export interface AppState {
  user: User;
};

Upvotes: 1

Views: 1736

Answers (1)

Vamshi
Vamshi

Reputation: 9331

Seeing your syntax, it looks like you are using older ngrx ( version 2 ) . The newer (version 4) is little different. I will give syntax for the older version here as you are already using it .

Your action code is correct, just remove @Injectable we are not injecting it anywhere. Reducer also seems fine.

If you want to access in your user service the code needs to be this way:

import { Store } from '@ngrx/store';    

@Injectable()
public class UserService{
    constructor(private store: Store<any>){}
    public getUser(): Observable<User>{
       return this.store.select('userReducer');
    }
}

This is not the best way , but if you get something working, you can improve it further.

In your component you can say

constructor(private userService: UserService){
    this.userService.getUser().subscribe((user: User)=> console.log(user));
}

Upvotes: 2

Related Questions