The projection of state in NGRX Store.select is not accurately reflected

Every time I run the following code:

valueToDisplay$ =store.select('model','sub-model')

The value stored in valueToDisplay$ always corresponds to 'model'. Despite trying various approaches to properly project the state, it seems that I am missing a crucial aspect of how the NGRX store initializes.

AppComponent
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { StoreModule } from '@ngrx/store';


import { AppComponent } from './app.component';
import { SetViewComponent } from './set-view/set-view.component';
import { MoveInputComponent } from './move-input/move-input.component';
import { MoveViewComponent } from './move-view/move-view.component';
import { movementsReducer } from './shared/store/set.store';



@NgModule({
  declarations: [
    AppComponent,
    SetViewComponent,
    MoveInputComponent,
    MoveViewComponent,
  ],
  imports: [
    BrowserModule,
    StoreModule.forRoot({movementsReducer:movementsReducer})
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Reducer: Despite having an extensively layered state object, it does not alter my core strategy so far.

import { DanceSet, Movement } from "../model/model";
import { Action, ActionReducerMap } from "@ngrx/store";
import { Injectable } from "@angular/core";
// STATE
export interface MovementState {
    movementsReducer:{
        movements?:Movement[],
        lastId?:number
    },
}
export const INITIAL_STATE:MovementState = {
    movementsReducer:{movements:[],lastId:0},

}
// ACTION NAMES
export enum MovementActionTypes  {
    ADD_MOVEMENT='[MOVEMENT] ADD_MOVEMENT',
    REMOVE_MOVEMENT='[MOVEMENT] REMOVE_MOVEMENT'
}

// ACTION CLASSES
export class AddMovementAction implements Action {
    readonly type = MovementActionTypes.ADD_MOVEMENT;
    constructor(public payload: Movement){};
}
export class RemoveMovementAction implements Action{
    readonly type =  MovementActionTypes.REMOVE_MOVEMENT;
    constructor(public payload:number){};
}

// Action TYPES
export type MovementActions
    = AddMovementAction | RemoveMovementAction

//Util
export function filterOutMovement(movements:Movement[], id:number):Movement[]{
    return movements.filter(item =>item.id !== id);
}

// Dance Set Reducer
export function movementsReducer(state: MovementState = INITIAL_STATE, action:any ): MovementState{
    switch(action.type){
        case MovementActionTypes.ADD_MOVEMENT:
            return {
                ...state,
                movementsReducer:{movements: [...state.movementsReducer.movements, action.payload], lastId:state.movementsReducer.lastId+1},
            }
        case MovementActionTypes.REMOVE_MOVEMENT:
            return{
             ...state,
                movementsReducer:{movements:filterOutMovement(state.movementsReducer.movements,action.payload), lastId:state.movementsReducer.lastId}
            }   
    default:
        return state;
    }
}

Current View Component: In my template, I aim to display the current 'movements$', but upon inspecting the object, it appears to be the entire state rather than a slice of it.

import { Component, OnInit } from '@angular/core';
import { MovementState, MovementActionTypes, AddMovementAction } from '../shared/store/set.store';
import { Store, select } from '@ngrx/store';
import { Movement } from '../shared/model/model';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'app-set-view',
  templateUrl: './set-view.component.html',
  styleUrls: ['./set-view.component.css']
})
export class SetViewComponent implements OnInit {
  public movements$:Array<Movement>;
  subscription;

  constructor(private store:Store<MovementState>) { 
    this.subscription = this.store.select('movementsReducer', 'movements').subscribe(value => this.movements$=value);
  }

  ngOnInit() {
  }

  addMove(name, id){
    let move = new Movement('Test',1);
    this.store.dispatch(new AddMovementAction(move));
  }

}

Answer №1

After implementing a Feature selector and a custom selector for the specific portion of state I needed, the issue was resolved. Despite initial indications from the API documentation that this step might not be necessary, it turned out to be essential.

import { createFeatureSelector, createSelector, ActionReducerMap, ActionReducer, MetaReducer } from "@ngrx/store";
import { MovementState, movementsReducer } from "./set.store";
import { environment } from "../../../environments/environment";

export interface AppState{
    movementState:MovementState;
}
export const getMovementState = createFeatureSelector<MovementState>('movementState');

export const getMovements = createSelector(
    getMovementState,
    (state:MovementState) => state.movementReducer.movements
)
export const getLastId = createSelector(
    getMovementState,
    (state:MovementState) => state.movementReducer.lastId
)

export const reducers: ActionReducerMap<AppState>={
    movementState:movementsReducer
}

export function logger(reducer: ActionReducer<AppState>): ActionReducer<AppState> {
    return function(state: AppState, action: any): AppState {
      console.log('state', state);
      console.log('action', action);
      return reducer(state, action);
    };
  } 


export const metaReducers: MetaReducer<AppState>[] = !environment.production
? [logger]
: []; 

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

Using a static value in the comparator is necessary for Array.find to function properly in Typescript

Looking to retrieve an item from an array: const device = this.selectedDevtype.devices.find(item => console.log(this.deviceID); return item.device_id === this.deviceID; }); console.log(device); When this.deviceID is logged, it shows "4", but t ...

Using forEach in React to simultaneously set multiple properties and return destructured output within the setState function

The following is the initial code snippet: setRows((rows) => rows.map((row) => selected && row.node === selected.id ? { ...row, row.a: "", row.b: "", row.c: "" } ...

The RxJs 'from' function is currently producing an Observable that is unrecognized

import { Tenant } from './tenant'; import { from, Observable } from 'rxjs'; export const testTenants: Tenant[] = [ { 'tenant_id': 'ID1' } ] const tenants$: Observable<Tenant>= from(testTenant ...

What is the best way to rearrange (exchange) elements within an Immutable Map?

Is there a way to rearrange items within an unchangeable list that is part of a Map? Here's an example: const Map = Immutable.fromJS({ name:'lolo', ids:[3,4,5] }); I have attempted to use the splice method for swapping, as well as ...

Is it possible for me to tap into the component creation process within the Angular Router?

Inspiration struck me when I realized the potential of adding a directive to the component designed for this particular route. It would elevate the functionality by letting me convey crucial information in a more declarative manner. Despite learning that ...

Should I implement jquery within angular 2, or opt for the current css/js frameworks available?

Embarking on the development of a website with Angular 2, my deadline is set within a month. I need to select a CSS/JS framework that seamlessly integrates with Angular 2. While using jQuery within Angular 2 is discouraged, I am curious if there are altern ...

Navigating with Angular: Transmitting dynamic URL parameters to components

I currently have the following routes defined: const routes: Routes = [ { path: ':product/new', children: [{ path: 'std/:country', component: SignUpComponent, data: { ...

How can I clear the cache for GetStaticPaths in NextJs and remove a dynamic route?

This question may seem basic, but I can't seem to find the answer anywhere online. Currently, I am diving into NextJs (using TypeScript) and I have successfully set up a site with dynamic routes, SSR, and incremental regeneration deployed on Vercel. ...

A TypeScript example showcasing a nested for-of loop within several other for loops

Is it possible to generate values from an Array of objects in the following way? const arr = [ { type: "color", values: [ { name: "Color", option: "Black", }, { name: "C ...

Encountering a problem with Angular 11 SSR after compilation, where the production build is causing issues and no content is being displayed in

{ "$schema":"./node_modules/@angular/cli/lib/config/schema.json", "version":1, "newProjectRoot":"projects", "projects":{ "new-asasa":{ "projectType": ...

What is the best way to send serverside parameters from ASP.Core to React?

After setting up a React/Typescript project using dotnet new "ASP.NET Core with React.js", I encountered the following setup in my index.cshtml: <div id="react-app"></div> @section scripts { <script src="~/dist/main.js" asp-append-versi ...

Running a Vue.js 3 application with TypeScript and Vite using docker: A step-by-step guide

I am currently facing challenges dockerizing a Vue.js 3 application using Vite and TypeScript. Below is my Dockerfile: FROM node:18.12.1-alpine3.16 AS build-stage WORKDIR /app COPY package.json ./ RUN yarn install COPY . . RUN yarn build-only FROM ngin ...

What is the process for deploying a Lambda function using Terraform that has been generated with CDKTF

Currently, I am following a tutorial by hashicorp found at this link. The guide suggests using s3 for lambda deployment packages. // in the process of creating Lambda executable const asset = new TerraformAsset(this, "lambda-asset", { ...

It is not possible to install Angular CLI on a Mac computer

My Mac computer is currently running macOS Ventura 13.1 I managed to install node (v18.12.1) & npm (8.19.2) successfully on the system. However, when I attempted to run npm install -g @angular/cli to install Angular CLI, it resulted in the following e ...

Loop through every element in the Angular2 template

I am working with the following template and I need to access all the elements within it. Using ViewChildren only gives me a reference to one element, most likely because no two elements are the same and I am not using the same directive/component inside t ...

How to effectively close an Angular material dialog with active ngForm?

Is it possible to close a dialog when using ngForm? I have multiple dialogs that appear before the final one, and I know how to get data using [mat-dialog-close]="true" along with MAT_DIALOG_DATA. However, in this last dialog, I am using ngForm t ...

Vertical and horizontal tabs not functioning properly in Mat tabs

I successfully created a vertical material tab with the code below, but now I am looking to incorporate a horizontal tab inside the vertical tab. Attempting to do so using the code provided results in both tabs being displayed vertically. Below is my code ...

The NextJS application briefly displays a restricted route component

I need to ensure that all routes containing 'dashboard' in the URL are protected globally. Currently, when I enter '/dashboard', the components display for about a second before redirecting to /login Is there a way to redirect users to ...

Tips for generating a subprocess with exec within a TypeScript Class

I am looking to automate the process of creating MRs in GitLab. When a button is clicked in my React/Typescript UI, I want to trigger command-line code execution within my Typescript class to clone a repository. However, every time I attempt to use exec, I ...

Error: Property 'instance' is undefined and cannot be read

Trying to confirm the functionality of the following method: showSnackbar(): void { if (this.modifiedReferences.length) { const snackbar = this.snackbarService.open({ message: '', type: 'success', durat ...