Home > front end >  Ngrx : Can't display objects - Angular Nx
Ngrx : Can't display objects - Angular Nx

Time:06-13

I implemented a ngrx solution and I am trying to display some objects named bookmarks in my project.

I don't know why my bookmarks are not beeing displayed on storybook even thought everything works perfectly :

These are my actions :

import {Action} from '@ngrx/store';
import { Bookmark } from '../models/bookmark';

export enum BookmarkActionsTypes {
    GET_BOOKMARKS = 'GET_BOOKMARKS',
    GET_BOOKMARKS_SUCCESS = 'GET_BOOKMARKS_SUCCESS',
    GET_BOOKMARKS_ERROR = 'GET_BOOKMARKS_ERROR',

    DELETE_BOOKMARK = 'DELETE_BOOKMARK',
    DELETE_BOOKMARK_SUCCESS = 'DELETE_BOOMARK_SUCCESS',
    DELETE_BOOKMARK_ERROR = 'DELETE_BOOKMARK_ERROR',

}


export class GetBookmarks implements Action{
    readonly type = BookmarkActionsTypes.GET_BOOKMARKS;
}

export class GetBookmarksSuccess implements Action{
    readonly type = BookmarkActionsTypes.GET_BOOKMARKS_SUCCESS;

    constructor(public payload : Bookmark[]){}
}


export class GetBookmarksError implements Action{
    readonly type = BookmarkActionsTypes.GET_BOOKMARKS_ERROR;

    constructor(public payload : string){}
}

export class DeleteBookmark implements Action{
    readonly type = BookmarkActionsTypes.DELETE_BOOKMARK;

    constructor(public payload : number){}
}

export class DeleteBookmarksSuccess implements Action{
    readonly type = BookmarkActionsTypes.DELETE_BOOKMARK_SUCCESS;

}


export class DeleteBookmarksError implements Action{
    readonly type = BookmarkActionsTypes.DELETE_BOOKMARK_ERROR;

    constructor(public payload : string){}
}



export type BookmarkActions = GetBookmarks | GetBookmarksSuccess | GetBookmarksError | DeleteBookmark | DeleteBookmarksSuccess | DeleteBookmarksError ;

These are my reducers :

import { createEntityAdapter, EntityAdapter, EntityState } from "@ngrx/entity";
import { Bookmark} from "../models/bookmark";
import { BookmarkActions, BookmarkActionsTypes } from "./actions";

export interface State extends EntityState<Bookmark>{
    error:string;
}

export const bookmarkAdapter:EntityAdapter<Bookmark> = createEntityAdapter<Bookmark>();

const defaultBookmarks = {
    error:''
}

const initialState : State = bookmarkAdapter.getInitialState(defaultBookmarks);

export function BookmarkReducer(state:State=initialState, action : BookmarkActions):State{
    switch(action.type){
        case BookmarkActionsTypes.GET_BOOKMARKS:
            return {...state, error:''};
        case BookmarkActionsTypes.GET_BOOKMARKS_SUCCESS:
            return bookmarkAdapter.setAll(action.payload,{...state, error:''});
        case BookmarkActionsTypes.GET_BOOKMARKS_ERROR:
            return {...state,  error:action.payload};

            case BookmarkActionsTypes.DELETE_BOOKMARK:
                return bookmarkAdapter.removeOne(action.payload,{...state, error:''});
            case BookmarkActionsTypes.DELETE_BOOKMARK_SUCCESS:
                return {...state, error:''};
            case BookmarkActionsTypes.DELETE_BOOKMARK_ERROR:
                return {...state, error:action.payload};


        default:{return state;}
    }
}

These are my selectors :

import { createFeatureSelector, createSelector } from "@ngrx/store";
import { Bookmark } from "../models/bookmark";
import { State, bookmarkAdapter } from "./reducers";

import {EntitySelectors, EntityState} from '@ngrx/entity/src/models';


export const getBookmarkState = createFeatureSelector<State>('angular');

export const {
    selectAll: selectAllBookmarks,
}:EntitySelectors<Bookmark, EntityState<Bookmark>> = bookmarkAdapter.getSelectors();

export const selectAll = createSelector(getBookmarkState, selectAllBookmarks);

export const selectError = createSelector(getBookmarkState, (state:State):string=>state.error);

And these are my effects :

import { Actions, ofType } from "@ngrx/effects";
import { catchError, map, Observable, of, switchMap } from "rxjs";
import { BookmarksService } from "../services/bookmarks-service.service";
import {Action} from '@ngrx/store';

import * as fromTodoActions from './actions';
import { Bookmark } from "../models/bookmark";
import { Injectable } from "@angular/core";

@Injectable({
    providedIn:'root'
})

export class BookmarksEffects {
   
    getBookmarks$:Observable<Action>=this.actions$.pipe(
        ofType(fromTodoActions.BookmarkActionsTypes.GET_BOOKMARKS),
        switchMap(()=>this.todoService.getBookmarks().pipe(
            map((bookmarks:Bookmark[]) => new fromTodoActions.GetBookmarksSuccess(bookmarks)),
            catchError((err:string)=>of(new fromTodoActions.GetBookmarksError(err))
        ))
    )
    )

    

  
    deleteTodo$:Observable<Action>=this.actions$.pipe(
        ofType(fromTodoActions.BookmarkActionsTypes.DELETE_BOOKMARK),
        switchMap((action)=>{return this.todoService.deleteBookmark(action.payload).pipe(
            map((bookmark:Bookmark[]) => new fromTodoActions.DeleteBookmarksSuccess()),
            catchError((err:string)=>of(new fromTodoActions.DeleteBookmarksError(err))
        ))}
    )
    )

    constructor(private actions$ : Actions<fromTodoActions.BookmarkActions>, private todoService : BookmarksService){}
}

I've created a json server and I am trying to display the contents of this file named bookmarks.json :

{
  "bookmarks": [
    {
      "id":123456,
      "name":"Zeke",
      "code":"93ac3Walk3r"
    },
    {
      "id":242668,
      "name":"Rex",
      "code":"ShadowMoses"
    },
    {
      "id":849761,
      "name":"Ray",
      "code":"Tanker"
    }
  ]
}

Finally this is the component.ts where I am trying to display the bookmarks :

    import { EventEmitter, Output, Input } from '@angular/core';
    import { Component} from '@angular/core';
    import { Bookmark } from '../../models/bookmark';
    import { BookmarksService } from '../../services/bookmarks-service.service';
    import {MatSnackBar} from '@angular/material/snack-bar';
    
    import * as fromBookmarkReducers from '../../store/reducers';
    import * as fromBookmarkActions from '../../store/actions';
    import * as fromBookmarkSelectors from '../../store/selectors';
    import { select, Store } from '@ngrx/store';
    
    @Component({
      selector: 'bookmark-bookmark-list',
      templateUrl: './bookmark-list.component.html',
      styleUrls: ['./bookmark-list.component.scss']
    })
    export class BookmarkListComponent{
    
    
      bookmarks$ : Observable<Bookmark[]>;
  state=false;

  constructor(private bookmarksService : BookmarksService,private _snackBar: MatSnackBar, private store:Store<fromBookmarkReducers.State>) {
    this.bookmarks$ = this.store.pipe(select(fromBookmarkSelectors.selectAll))
     
      
    this.store.dispatch(new fromBookmarkActions.GetBookmarks());
   }
     
    
      @Output() click: EventEmitter<void> = new EventEmitter();
    
     
    
      onDelete(bookmark:Bookmark) {
        this.store.dispatch(new fromBookmarkActions.DeleteBookmark(bookmark.id));
      }
    
     
    
      onclick(){
        this.click.emit();
        }
    
      @Input()
      backgroundColor?:string;
    
      @Input()
      Color: 'white' | 'black';
    
    }

And this is its template :

<div >
    
    <div  [ngStyle]="{'background-color':backgroundColor}">
        <h3>Bookmarks</h3>
        <mat-nav-list role="navigation">
            
            <p  *ngIf="state">No bookmarks...</p>
            
            <mat-list-item *ngFor="let bookmark of bookmarks$ |async">
              
                <a matLine  [ngStyle]="{'color':Color}" (click)="onclick()">{{bookmark.name}} , {{bookmark.code}}, {{bookmark.id}}</a>
                <button mat-icon-button (click)="onDelete(bookmark)">
                    <mat-icon>delete_outline</mat-icon>
                </button>
                
            </mat-list-item>
            
        </mat-nav-list>
      

</div>

Oh yes ! And this is the service (almost forgot) :

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable} from 'rxjs';
import { Bookmark } from '../models/bookmark';


@Injectable({
  providedIn: 'root'
})
export class BookmarksService {

  apiURL = 'http://localhost:3000/bookmarks/';

  constructor(private http : HttpClient) { }

  getBookmarks():Observable<Bookmark[]>{
    return this.http.get<Bookmark[]>(this.apiURL)
  }


  deleteBookmark(id:number){
    return this.http.delete<any>(this.apiURL id)
    
  }

}

And I had forgot the library module :

import { CUSTOM_ELEMENTS_SCHEMA, NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import {MatSidenavModule} from '@angular/material/sidenav';
import {MatIconModule} from '@angular/material/icon';
import { BookmarkListComponent } from './components/bookmark-list/bookmark-list.component';
import { RouterModule, Routes } from '@angular/router';
import { HttpClientModule } from '@angular/common/http';
import { BookmarksService } from './services/bookmarks-service.service';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {MatButtonModule} from '@angular/material/button';
import {MatListModule} from '@angular/material/list';
import {MatSnackBar, MatSnackBarModule} from '@angular/material/snack-bar';
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { BookmarksEffects } from './store/effects';
import { BookmarkReducer } from './store/reducers';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
const routes : Routes = [
  {path:'', component:BookmarkListComponent}
]

const material = [
  MatSidenavModule, 
  MatIconModule, 
  MatButtonModule,
  MatListModule,
  MatSnackBarModule,
  
];


@NgModule({
  imports: [
    CommonModule,
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule, 

    ...material,

    RouterModule.forRoot(routes, {initialNavigation: 'enabled'}),
    StoreModule.forRoot({angular:BookmarkReducer}),
    EffectsModule.forRoot([BookmarksEffects]),
    StoreDevtoolsModule.instrument({maxAge:10}),
  ],
  declarations: [
  
  
    BookmarkListComponent,
         
  ],
  providers: [BookmarksService, HttpClientModule],
  schemas: [ CUSTOM_ELEMENTS_SCHEMA ],
  exports: []
})
export class LibModule {}

CodePudding user response:

In you effect file the effects must be nested in the createEffect() function.

Like this :

getBookmarks$:Observable<Action> = createEffect(() =>  
this.actions$.pipe(
        ofType(fromTodoActions.BookmarkActionsTypes.GET_BOOKMARKS),
        switchMap(()=>this.todoService.getBookmarks().pipe(
            map((bookmarks:Bookmark[]) => new fromTodoActions.GetBookmarksSuccess(bookmarks)),
            catchError((err:string)=>of(new fromTodoActions.GetBookmarksError(err))
        ))
    )
    )
);

This should do the trick. The rest of your code looks ok.

  • Related