Choosing everything with ngrx/entity results in not selecting anything

Issue with Selector

I am facing an issue with my selector in the component. Despite making the call, the component does not update with books from the FakeApiService. The actions and effects seem to be functioning correctly.

The problem seems to be related to my usage of @ngrx/Entity. Specifically this:

export const getBooksState = createFeatureSelector<DemoState>('demo');

and

export const { selectAll } = fromBook.adapter.getSelectors();

I have referred to tutorials where they provide a selector function to getSelectors(), but it doesn't seem necessary in my case.

I would appreciate it if someone could point out where I might be going wrong, and any suggestions regarding the structure/setup are welcome :)

Below is my setup:

Software Versions

  • Angular: 6.0.0
  • rxjs: 6.1.0
  • typescript: 2.7.2
  • webpack: 4.6.0
  • @ngrx/effects: 5.2.0
  • @ngrx/entity: 5.2.0
  • @ngrx/router-store: 5.2.0
  • @ngrx/schematics: 5.2.0
  • @ngrx/store: 5.2.0
  • @ngrx/store-devtools: 5.2.0

ngRx Setup

feature/store/actions/book.actions.ts

import { Action } from '@ngrx/store';
import { Book } from '../../models/book';

export enum BookActionTypes {
  Load = '[Book] Load',
  LoadSuccess = '[Book] Load Success',
  LoadFail = '[Book] Load Fail'
}

export class LoadBooksAction {
  readonly type = BookActionTypes.Load;
}

export class LoadBooksSuccessAction implements Action {
  readonly type = BookActionTypes.LoadSuccess;
  constructor(public payload: Book[]) {}
}

export class LoadBooksFailAction {
  readonly type = BookActionTypes.LoadFail;
}

export type BookActions
  = LoadBooksAction
  | LoadBooksSuccessAction
  | LoadBooksFailAction;

feature/store/effects/book.effects.ts

import { Injectable } from '@angular/core';
import { Actions, Effect } from '@ngrx/effects';
import { of } from 'rxjs';
import { catchError, map, switchMap } from 'rxjs/operators';
import { FakeApiService } from '../../services/fake-api.service';
import { LoadBooksFailAction, LoadBooksSuccessAction, BookActionTypes } from '../actions/book.actions';

@Injectable()
export class BookEffects {
    constructor(
        private fakeService: FakeApiService,
        private actions$: Actions,
    ) {}

    @Effect()
    loadBooks$ = this.actions$
      .ofType(BookActionTypes.Load)
      .pipe(
        switchMap(() => this.fakeService.getBooks()),
        map(books => (new LoadBooksSuccessAction(books))),
        catchError(error => of(new LoadBooksFailAction()))
      );
}

feature/store/reducers/book.reducer.ts

import { EntityState, createEntityAdapter } from '@ngrx/entity';
import { Book } from '../../models/book';
import { BookActionTypes, BookActions } from './../actions/book.actions';

export interface BooksState extends EntityState<Book> {}

export const adapter = createEntityAdapter<Book>();

const initialState: BooksState = adapter.getInitialState();

export function reducer(state = initialState, action: BookActions ): BooksState {
  switch (action.type) {
    case BookActionTypes.LoadSuccess: {
      return adapter.addAll(action.payload, state);
    }

    default: {
      return state;
    }
  }
}

feature/store/reducers/index.ts

import { ActionReducerMap, createFeatureSelector } from '@ngrx/store';
import * as fromOrder from './book.reducer';

export interface DemoState {
  demo: fromBook.BooksState;
}

export const reducers: ActionReducerMap<DemoState> = {
  demo: fromBook.reducer
};

export const getBooksState = createFeatureSelector<DemoState>('demo');

feature/store/selectors/book.selectors.ts

import * as fromBook from '../reducers/book.reducer';

export const {selectAll} = fromBook.adapter.getSelectors();

Angular Setup

feature/feature.module.ts

@NgModule({
  imports: [
    CommonModule,
    StoreModule.forFeature('demo', reducer),
    EffectsModule.forFeature([BookEffects])
  ],
  providers: [FakeApiService],
  declarations: []
})
export class DemoModule { }

feature/components/book-view.component.ts

@Component({
  selector: 'app-book-view',
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `<book-list [books]="books$ | async"></book-list>`
})
export class BookViewComponent implements OnInit {
  books$: Observable<Book[]>;

  constructor(private store: Store<fromStore.BooksState>) {
    this.books$ = this.store.pipe(select(fromStore.selectAll));
  }

  ngOnInit() {
    this.store.dispatch(new bookActions.LoadBooksAction());
  }
}

Answer №1

The issue lies within your Selector; You need to pass the book/demo state into the getSelectors functions

import * as fromBook from '../reducers/book.reducer';

import { getBooksState } from '../reducers';

export const selectBookState = createSelector(
  getBooksState,
  state => state.demo
);

export const {
  selectAll
} = fromBook.adapter.getSelectors(selectBookState);

Take a look at my repository and link

https://github.com/rijine/itunes-album-angular/blob/master/src/app/album/store/selectors/albums.selector.ts

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

Retrieve input value in Angular 8 using only the element's ID

Can the value of an input be obtained in Angular 8 with TypeScript if only the element's id is known? ...

Ways to store a component in cache once its route is triggered

There are 3 components in my project: 1 parent and 2 child components with router outlet. The child component becomes active whenever its route is called, sharing data using a service. Both of these child components have complex views. When switching bet ...

Dealing with Typescript (at-loader) compilation issues within a WebPack environment

Currently, I am using Visual Studio 2017 for writing an Angular SPA, but I rely on WebPack to run it. The current setup involves VS building the Typescript into JS, which is then utilized by WebPack to create the build artifact. However, I am looking to t ...

Apollo GraphQL has initiated the detection of a new subscription

My approach involves utilizing graphql-ws for subscribing to GraphQL events. I rely on the Observable interface to listen to these events. Although I can use the error callback to identify when a subscription fails to start, it is challenging to determine ...

Tips for cycling through the backend API map reaction in Angular or Typescript

When I make a call to an API, it returns a response in the form of a map: {thomas: 3, test70: 2, tim: 2, elin: 2, sumeet12: 1} I tried iterating over this response in Angular, but encountered an error. Error Encountered: This expression is not callab ...

Some elements that fit the criteria of 'number | function' are not callable at all

Consider a basic function like this: export const sum = (num?: number) => { const adder = (n: number) => { if (!n) { return num; } num = (num && num + n) || n; return adder; }; return a ...

Ways to verify whether a checkbox is selected and store the status in the LocalStorage

Hey there, I'm still new to the world of programming and currently just a junior developer. I have a list of checkboxes and I want to save any unchecked checkbox to my local storage when it's unselected. Below is a snippet of my code but I feel l ...

"The CanActivate guard leads to a redirection to the root path upon initial loading, causing the router-outlet to fail

Recently, I encountered an issue with my SPA configuration that involves the AuthGuard. The setup is such that if a user is not logged in, they are redirected to an error page. However, when the user is logged in, specific routes are accessible. Here’s a ...

Creating TypeScript utility scripts within an npm package: A Step-by-Step Guide

Details I'm currently working on a project using TypeScript and React. As part of my development process, I want to automate certain tasks like creating new components by generating folders and files automatically. To achieve this, I plan to create u ...

What could be causing MongoDB to not delete documents on a 30-second cycle?

Having trouble implementing TTL with Typegoose for MongoDB. I am trying to remove a document from the collection if it exceeds 30 seconds old. @ObjectType("TokenResetPasswordType") @InputType("TokenResetPasswordInput") @index( { cr ...

"Utilizing Angular's Reactive Forms to Set a Default Object in

I'm having an issue with setting the default value for a select box in my reactive form. The select options come from an array of objects, but no matter what I try, the default value just won't stick. This is how my form looks like: <form [f ...

Displaying Mat-error from response in Angular and Django user authentication process is not functioning as expected

Currently, I am working on the Signup page and facing an issue with handling 'if username already Exists'. I have successfully logged the Error message I want to display in the Console but it is not appearing on the Mat-error Label. This snippet ...

Stop MatDialog instance from destroying

In my application, I have a button that triggers the opening of a component in MatDialog. This component makes API calls and is destroyed when the MatDialog is closed. However, each time I open the MatDialog for the second time by clicking the button agai ...

Implement video.js within an Angular 2 application

I've been attempting to use video.js for my angular2 videos, but I've hit a roadblock. I have included the video.js CDN in my index file. <link href="https://vjs.zencdn.net/5.11/video-js.min.css" rel="stylesheet"> <script src="https://v ...

What is the best way to make cypress.io swipe an ionic ion-item-sliding component to the left?

I am currently working on a small ionic 4 (vue) app that includes an ion-list with ion-item-sliding. Here is a snippet of the code: HTML <ion-item-sliding v-for="day in month.days" v-bind:key="day.day"> <ion-item :id ...

How can I display data both as a dropdown and an autocomplete in Angular using a textbox?

There is a textbox with autocomplete functionality. When the user clicks on the textbox, an API call is made with two parameters - Pubid and Date. The data is then displayed in a dropdown with autocomplete feature. Now I am attempting to have the data app ...

Whenever the return condition is false, make sure to subscribe to the Angular CanActivate Guard

In my UserAccessGuard class, I have a method that captures the current path and compares it to the user's available paths. However, I am facing asynchronous problems because the condition inside the subscribe block causes my Hasaccess variable to rema ...

Converting a JSON array stored in a local file to a TypeScript array within an Angular 5 project

I'm currently working on developing a web app using Angular 5. My JSON file has the following structure: [ { "id": 0, "title": "Some title" }, { "id": 1, "title": "Some title" }, ... ] The JSON file is store ...

Encountering an issue in Angular where data.slice is not functioning properly, resorting to using parseInt to convert strings into Date

Looking to convert the data retrieved from the database into numbers and dates with ease. One set of data is in milliseconds while the other is in timestamps. https://i.stack.imgur.com/HdM0D.png The goal is to transform both types into numbers first, the ...

When working with formControlName in Angular Material 2, the placeholder may overlap the entered value

After updating my application with angular-cli to angular/material (2.0.0-beta.11) and angular (4.4.4), I noticed that every placeholder in the material input fields overlaps the value when provided with formControlName in reactive forms. However, when usi ...