Error encountered in Angular NGRX while accessing the store: Trying to read property 'map' of an undefined variable

I have integrated NGRX effects into my Angular application and encountered the following error. I'm uncertain if I am using the selector correctly in my component to query the store?

core.js:6162 ERROR TypeError: Cannot read property 'map' of undefined
  at ngrx-entity.js:21
    at ngrx-store.js:1198
    at memoized (ngrx-store.js:1039)
    at defaultStateFn (ngrx-store.js:1079)
    at ngrx-store.js:1207
    at memoized (ngrx-store.js:1039)
    at ngrx-store.js:1078
    at Array.map (<anonymous>)

Component

ngOnInit() {
    this.initializeForModel();
    //this.users$ = this.store.select(getAllUsers);

    this.store.select(getAllUsers).pipe().subscribe((response:any)=> {
            this.listOfUser = response.users;
            this.userMange = this._createGroup();
        
      });
      
  

Selector

export const userFeatureSelector = createFeatureSelector<UserState>('users');

        export const getAllUsers = createSelector(
          userFeatureSelector,
          selectAll,
          selectIds
        );

Service

  constructor(private http: HttpClient) { }
          getAllUsers(): Observable<any> {
          return this.http.get("assets/user.json");
          }
        }

Reducer

  import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
           
           export interface UserState extends EntityState<User> {
      usersLoaded: boolean;
    }

export const adapter: EntityAdapter<User> = createEntityAdapter<User>();

export const initialState  = adapter.getInitialState({
  usersLoaded: false,
  users: [
  
  ],

});

export interface UserState {
  users: User[];
}
        
       export const userReducer = createReducer(
      initialState,
      on(UserActions.loadUsers, (state, { users }) => {
        return adapter.setAll(users, state);
      }),
      

  
  

Action

export const loadUsers = createAction(
      '[Users List] Load Users via Service',
      props<{ users: User[] }>()
    );

Effects

loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserActions.loadUsers),
     mergeMap(() => this.UserService.getAllUsers()
     .pipe(
       map(users => ({ type: UserActions.loadUsers.type, payload: users }))
     // map(users =>  { {console.log(users)} return UserActions.usersLoaded({users})})()
    ))
    )
  );
        

Answer №1

To utilize the map functionality within Effects, make sure to import it along with mergeMap and catchError from the rxjs/operators library. Here's an example:

import { map, mergeMap, catchError } from "rxjs/operators";

Answer №2

Have you noticed the missing return value from the selector? Also, the effect should be returning an action which it seems like yours is not doing. Are you encountering any errors as well? If you don't want to dispatch anything, consider adding { dispatch: false} as the second parameter to the createEffect() function.

export const getAllUsers = createSelector(
  userFeatureSelector,
  selectAll,
  selectIds
  (feature, all, ids) => ({ feature, all, ids }) // In VS Code, a faulty underline will appear under the selector without this line
);

EDIT: You can also try dispatching an action from the effect or marking it as an effect without dispatch

loadUsers$ = createEffect(() =>
  this.actions$.pipe(
    ofType(UserActions.loadUsers),
    mergeMap(() => this.UserService.getAllUsers()
      .pipe(
        map(users => ({ type: UserActions.loadUsers.type, payload: users }))
      ))
    ),
    { dispatch: false} // Add this parameter so that the effect does not need to dispatch a new action
  );

I don't have much experience with NgRx entity/data, but in general, reducers execute before effects. So if you expect data in your loadUsers reducer to come from the backend, you might be mistaken. You should handle it as an action first, and then upon successful BE call, dispatch a new action (like `saveUsers`) that will update the data.

EDIT 2: It seems I now understand what you were trying to achieve. Were you attempting to modify the payload of the loadUsers action using the effect? Consider this approach:

// actions
export const loadUsers = createAction('[Users List] Load Users via Service'); // empty 
export const saveUsers = createAction('[Users Effect] Save Users', props<{ users: User[] }>());

// reducer
on(UserActions.saveUsers, (state, { users }) => {
  return adapter.setAll(users, state);
}),

// effects
loadUsers$ = createEffect(() =>
  this.actions$.pipe(
    ofType(UserActions.loadUsers),
    concatMap(() => this.UserService.getAllUsers()),
    map(users => UserActions.saveUsers({ users }))       
  ));

If I interpret correctly, the error arises from NgRx Entity because the payload in your loadUsers reducer is undefined. Your attempt to update the payload in the effect actually occurs after the reducer execution.

Answer №3

While I wasn't able to replicate the specific error you mentioned, I managed to successfully resolve the issue with the store.

The basic structure of a store is as follows:

  1. Initiate an action

In this case, I modified the original action you were using to one without any payload.

Now, within my actions file, I defined two actions:

import { createAction, props } from "@ngrx/store";
import { User } from "../reducers/user.reducer";

export const loadUsers = createAction(
  "[Users List] Load Users"
);

export const loadUsersSuccess = createAction(
  "[Users List] Load Users Success",
  props<{ users: User[] }>()
);

And in the component, we would have:

this.store.dispatch(loadUsers());
  1. The Effect receives the action and triggers another action

Once an action is dispatched, the effect will capture it. We then need to invoke the service, fetch data, and trigger a new action with the desired payload.

@Injectable()
export class UserEffects {
  loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UserActions.loadUsers),
      mergeMap(() => this.UserService.getAllUsers()),
      map(users => UserActions.loadUsersSuccess({users}))
    )
  );

  constructor(private actions$: Actions, private UserService: MyService) {}
}

  1. The Reducer captures the action and stores the data

export const userReducer = createReducer(
  initialState,
  on(UserActions.loadUsers, state => {
    return adapter.setAll(state.users, state);
  }),
  on(UserActions.loadUsersSuccess, (state, { users }) => {
    return adapter.setAll(users, state);
  })
);

Check out a demo on StackBlitz for reference.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

The DataGrid is only displaying a single result instead of multiple results

I'm having difficulty displaying all the results in this MUI data table. Currently, it is only showing one result instead of all, and I can't figure out what I'm doing wrong. If you have any suggestions or best practices on how to properly ...

With *ngFor in Angular, radio buttons are designed so that only one can be selected

My goal is to create a questionnaire form with various questions and multiple choice options using radio buttons. All the questions and options are stored in a json file. To display these questions and options, I am utilizing nested ngFor loops to differ ...

Deactivate multiple input fields by utilizing various radio buttons

I need help with enabling and disabling input fields based on radio button selection. When the first radio button is selected, I want to disable three input fields, when the second is selected, only two specific input fields should be enabled (SHIFT START ...

Oops! A mistake was made by passing an incorrect argument to a color function. Make sure to provide a string representation of a color as the argument next time

Encountering an issue with a button react component utilizing the opacify function from the Polished Library The styling is done using styled-components along with a theme passed through ThemeProvider. Upon testing the code, an error is thrown. Also, the ...

The template is displaying the string as "[object Object]"

I've implemented code in my ngOnInit function to fetch the translation for a specific text. The following function is being called: async getEmailTranslation() { const email$ = this.translate.get('SUPPORT_TRANSLATE.EMAIL'); this.emai ...

Functions designed to facilitate communication between systems

There is an interface that is heavily used in the project and there is some recurring logic within it. I feel like the current solution is not efficient and I am looking for a way to encapsulate this logic. Current code: interface Person { status: Sta ...

Issue with getStaticProps in Next.js component not functioning as expected

I have a component that I imported and used on a page, but I'm encountering the error - TypeError: Cannot read property 'labels' of undefined. The issue seems to be with how I pass the data and options to ChartCard because they are underline ...

Ways to incorporate style links in Angular v2 components?

Currently, I am working through the Angular tutorial available on their website. In my quest to create various components, templates, and styles, I have hit a roadblock. The issue lies in incorporating my styles into the components using the 'styleUR ...

Tips for adding and verifying arrays within forms using Angular2

Within my JavaScript model, this.profile, there exists a property named emails. This property is an array composed of objects with the properties {email, isDefault, status}. Following this, I proceed to define it as shown below: this.profileForm = this ...

TypeScript - Converting into individual compiled files

Currently, I am working on a project that consists of lengthy source files. While this is advantageous for imports, it poses challenges in terms of maintenance. For instance: /main/core.ts export type Foo { ... } export interface Bar { ... } export cla ...

Include a log out option in the side menu of the ionic2 application

I am working with the sidemenu template to kick off my application. I aim to incorporate a button within the sidemenu that enables users to trigger a modal alert for confirming logout. Below is the code snippet: app.component.ts: import { Component, View ...

What are the steps for changing this JavaScript file into TypeScript?

I'm currently in the process of converting this JavaScript file to TypeScript. However, I've encountered an error with the onClick function as shown below: import React from 'react'; import { Popover } from 'antd'; import A fr ...

Is it possible to determine the time format preference of the user's device in Angular? For example, whether they use a 24-hour system or a 12-hour system with AM

In Angular, is there a way to determine whether the user's time format is set to 24-hour or 12-hour system? Any help would be greatly appreciated. Thanks! ...

Enforcement of Typescript Field Type Lax During Assignment

My current issue involves a constructor that is supposed to set the value of _device. The field is specifically designed to be of type number, and the constructor parameter is also expected to be of type number. However, when a parameter of type string is ...

What is the best method to condense an array or extract only the valid values?

Looking to find the total count of properties that are true from an array of objects? Here's an example: let data = [ { comment: true, attachment: true, actionPlan: true }, { whenValue: '', ...

Is there a way to create fresh instances of a class using Injector rather than utilizing a singleton pattern?

In my Angular application, I am working with two injectable classes. @Injectable() class B {} @Injectable() class A { constructor(b:B) { } } My goal is to make class A a Singleton and class B a Transient. I recently discovered that I can utilize Ref ...

Counting nodes that have the 'enabled' property: A guide

I am dealing with a tree structure that has Node objects: class Node implements ITreeNode { id?: any; name: string; children:? Node[], enabledState = new Subject<boolean>(); toggle() { this.enabled = !this.enabled; this.enabledStat ...

Is the utilization of the React context API in NextJS 13 responsible for triggering a complete app re-render on the client side

When working with NextJS 13, I've learned that providers like those utilized in the React context API can only be displayed in client components. It's also been made clear to me that components within a client component are considered part of the ...

Discover how to access and manipulate JSON files in an Angular application using

Currently, I am diving into learning TypeScript with Angular and I'm interested in reading a JSON file. The structure of my JSON file is as follows: { "nb": "7", "extport": "1176",, "REQ_EMAIL": ...

Tips for adjusting fullcalendar's local property in an Angular application

I'm having trouble changing the local property of fullcalendar. I've tried setting it to "en-gb", but it's not working. Can you help me figure out what I'm doing wrong? <full-calendar #calendar defaultView="dayGridMonth" [header]="{ ...