Or Yaacov
Or Yaacov

Reputation: 3880

Angular ngrx 8 selector doesn't return any value

I'm not new to Angular but I'm new to ngrx. I'm trying to get some values from my server and simply print them to the screen, I can see that the values are returning from the server after that the effect catches the action and do it's job:

enter image description here

but then my simple component doesn't show anything:

ProfileComponent.ts:

export class ProfileComponent implements OnInit {
  network$= this.store.select(a=>a.NetworkInfo)
  profiles$: Observable<Profile[]> = this.store.select(state => state.Profiles);
  constructor(private store:Store<NetAlertState>) { }

  ngOnInit() {
    this.store.dispatch({ type: '[Profile Component] getAllProfiles' });
    this.store.dispatch({ type: '[Profile Component] getNetworkInfo' });    
  }

}

profile.component.html:

    <div *ngFor="let profile of profiles$ | async">
    {{ profile.name }}
    </div>

net-alert.actions.ts:

export const getAllProfiles = createAction('[Profile Component] getAllProfiles');
export const getNetworkInfo = createAction('[Profile Component] getNetworkInfo');
export const loadProfilesSuccess = createAction('[Profile Component] loadProfilesSuccess',props<{items:Profile[]}>());
export const loadNetworkInfoSuccess = createAction('[Profile Component] loadNetworkInfoSuccess', props<NetworkInfo>());
export const loadProfilesFailure = createAction('[Profile Component] loadProfilesFailure',props<String>());
export const loadNetworkInfoFailure = createAction('[Profile Component] loadNetworkInfoFailure',props<String>());

net-alert.reducer.ts

    export const initialState: NetAlertState = {
    Profiles:null,
    NetworkInfo:null,
    isLoading: false,
    error: null
}

export const NetAlertReducer = createReducer(
    initialState,
    on(NetAlertActions.getAllProfiles, state => ({ ...state,isLoading:true ,error:null})),
    on(NetAlertActions.loadProfilesSuccess, (state,profiles) => ({ Profiles:profiles,...state ,isLoading:false ,error:null})),
    on(NetAlertActions.loadProfilesFailure, (state,err) => ({ ...state,isLoading:false ,error:err})),
    on(NetAlertActions.getNetworkInfo, state => ({ ...state ,isLoading:true ,error:null})),
    on(NetAlertActions.loadNetworkInfoSuccess, (state,res) => ({ ...state,NetworkInfo:res,isLoading:false ,error:null})),
    on(NetAlertActions.loadNetworkInfoFailure, (state,err) => ({ ...state,isLoading:false ,error:err})),
  );



export function reducer(state: NetAlertState | undefined, action: Action) {
    return NetAlertReducer(state, action);
  }

net-alert.effects.ts:

@Injectable()
export class NetAlertEffects {

    loadProfiles$ = createEffect(() =>
     this.actions$.pipe(
        ofType('[Profile Component] getAllProfiles'),
        mergeMap(() => this.dataService.getAllProfiles()
          .pipe(
            map(res => ({ type: '[Profile Component] loadProfilesSuccess', payload: res })),
            catchError(() => of({ type: '[Profile Component] loadProfilesFailure' }))
          )
        )
      )
  );

  constructor(
    private actions$: Actions,
    private dataService: DataService
  ) {}
}

net-alert.state.ts:

  export interface NetAlertState {
     isLoading: boolean;
     error: any;
     NetworkInfo: NetworkInfo;
     Profiles: Profile[];
 }

 export interface Profile {
  Mac: string;
  NickName: string;
  CreateDate: Date;
  Sites?: any;
}

root-state.ts:

export interface AppStates {
  netAlert: NetAlertState;
}

export const netAlertReducers: ActionReducerMap<AppStates> = {
    netAlert: netAlertRerucers.reducer
 }; 

app.module.ts:

  @NgModule({
  declarations: [
    AppComponent,
    ProfileContainerComponent,
    ProfileComponent
  ],
  imports: [
    HttpClientModule,
    BrowserModule,
    AppRoutingModule,
    StoreModule.forRoot(netAlertReducers),
    EffectsModule.forRoot([NetAlertEffects]),
    StoreDevtoolsModule.instrument({
      maxAge: 25, // Retains last 25 states
      logOnly: environment.production, // Restrict extension to log-only mode
    }),
    RootStoreModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

is anyone can tell me where is my mistake?

Thanks a lot!

Upvotes: 1

Views: 3188

Answers (3)

Tony
Tony

Reputation: 20092

You should put your profiles$ in ngOnInit method like this

export class ProfileComponent implements OnInit {
  network$: any;
  profiles$: Observable<Profile[]>
  constructor(private store:Store<NetAlertState>) { }

  ngOnInit() {
    this.store.dispatch({ type: '[Profile Component] getAllProfiles' });
    this.store.dispatch({ type: '[Profile Component] getNetworkInfo' });
    this.network$ =  this.store.select(a=>a.NetworkInfo);
    this.profiles$ = this.store.pipe(select(state => state.Profiles));
  }
}

Also try to use pipe operator

Upvotes: 1

Andrew Allen
Andrew Allen

Reputation: 8002

I don't see a selector for selecting the "netAlert" state, upon which you build the other selectors, like so:

selectors.ts

import * as fromNetAlertState from "./state";

export const netAlertState = (state: State) => state.netAlert;

export const selectProfiles = createSelector(
  netAlertState,
  (state: fromNetAlertState.State) => state.Profiles
);

component.ts

profiles$: Observable<Profile[]> 

ngOnInit() {
    this.profiles$ = this.store.pipe(select(selectProfiles))
}

Upvotes: 1

HTN
HTN

Reputation: 3604

It won't work if you don't have a reducer to update your state from loadProfilesSuccess action. Something like:

const myReducer = createReducer(
  initialState, // type NetAlertState
  on(from.loadProfilesSuccess, (state, action) => {
     // return new state from action payload
  }),
)

export function reducer(state: NetAlertState, action: Action) {
    return myReducer(state, action);
}

You have actions but you never used them as well. You should use them everywhere:

ngOnInit() {
    this.store.dispatch(getAllProfiles());
    this.store.dispatch(getNetworkInfo());
}
loadProfiles$ = createEffect(() =>
     this.actions$.pipe(
        ofType(getAllProfiles),
        mergeMap(() => this.dataService.getAllProfiles()
          .pipe(
            map(res => loadProfilesSuccess(res)),
            catchError(() => of(loadProfilesFailure())
          )
        )
      )
    );

Upvotes: 1

Related Questions