currently i am trying to integrate the awesome ngrx lib into my project. Everything works as intended expect for the @ngrx/effects lib. What i am trying to do is to get some of my data from a service which will make a http request later on. I know that i am missing something but i can`t find my misunderstanding. Maybe some of you can help.
So i have a lazy loaded module within my application where i want to use the ngrx lib.
My code so far:
app.module.ts
import [...]
import { StoreModule } from '@ngrx/store';
import { StoreDevtoolsModule } from '@ngrx/store-devtools';
import { EffectsModule } from '@ngrx/effects';
@NgModule({
imports: [
HttpModule,
BrowserModule,
BrowserAnimationsModule,
ToastModule.forRoot(),
FormsModule,
SharedModule,
ReactiveFormsModule,
appRouting,
StoreModule.forRoot({}),
StoreDevtoolsModule.instrument({
maxAge: 25
}),
EffectsModule.forRoot([])
],
declarations: [
AppComponent,
NavigationComponent,
HomeComponent,
LoginComponent,
SidebarComponent,
PageNotFoundComponent
],
providers: [
AuthenticationService,
AlertService,
AuthGuard,
mockBackendProvider,
MockBackend,
BaseRequestOptions,
AppConfig,
{
provide: APP_INITIALIZER,
useFactory: (config: AppConfig) => () => config.load(),
deps: [AppConfig],
multi: true
},
{
provide: ToastOptions, useClass: NotificationOptions
}
],
bootstrap: [AppComponent]
})
export class AppModule {
}
project.module
import [...]
import { StoreModule } from '@ngrx/store';
import { EffectsModule } from '@ngrx/effects';
import { projectReducer } from './store/project.reducer';
import { ProjectService } from './services/project.service';
import { ProjectEffects } from './store/project.effects';
@NgModule({
imports: [
CommonModule,
FormsModule,
ReactiveFormsModule,
ProjectRoutingModule,
SharedModule,
EffectsModule.forFeature([ProjectEffects]),
StoreModule.forFeature('projectModule', {
projectReducer: projectReducer,
}),
],
exports: [],
declarations: [
HomeComponent,
DashboardComponent
],
providers: [
ProjectService,
mockBackendProvider,
MockBackend,
BaseRequestOptions
],
})
export class ProjectModule {
}
I created 4 files:
project.actions.ts
import { Action } from '@ngrx/store';
import { Project } from '../../../models/Project/Project';
export const SELECT_ALL_PROJECTS = '[projects] Select all';
export const ADD_PROJECT = '[projects] Add project';
export const DELETE_PROJECT = '[projects] Delete project';
export class GetAllProjectsAction implements Action {
readonly type = SELECT_ALL_PROJECTS;
constructor(public projects: Project[]) {
}
}
export class AddProjectAction implements Action {
readonly type = ADD_PROJECT;
constructor(public project: Project) {
}
}
export class DeleteProjectAction implements Action {
readonly type = DELETE_PROJECT;
constructor(public project: Project) {
}
}
export type Actions = GetAllProjectsAction | AddProjectAction | DeleteProjectAction;
projects.effects.ts
import { Injectable } from '@angular/core';
import {
Actions,
Effect
} from '@ngrx/effects';
import { Observable } from 'rxjs/Observable';
import { Action } from '@ngrx/store';
import * as projectAction from './project.actions';
import { ProjectService } from '../services/project.service';
import { of } from 'rxjs/observable/of';
@Injectable()
export class ProjectEffects {
@Effect() getAll$: Observable<Action> = this.actions$.ofType(projectAction.SELECT_ALL_PROJECTS)
.mergeMap(() =>
this._projectService.getAll()
.map((data: any[]) => ({type: projectAction.SELECT_ALL_PROJECTS, projects: data}))
.catch((error: any) => {
return of({type: 'getALL_Failed'})
})
);
constructor(private _projectService: ProjectService, private actions$: Actions) {
}
}
projects.reducer.ts
import * as projectAction from './project.actions';
import { ProjectState } from './project.state';
export const initialState: ProjectState = {
projects: [
{id: 1, title: 'Project Alpha'}, {id: 2, title: 'Project Beta'}]
};
export function projectReducer(state = initialState, action: projectAction.Actions): ProjectState {
switch (action.type) {
case projectAction.ADD_PROJECT:
return Object.assign({}, state, {
projects: state.projects.concat(Object.assign([], state, action.project))
});
case projectAction.SELECT_ALL_PROJECTS:
return Object.assign({}, state, action.projects);
case projectAction.DELETE_PROJECT:
return Object.assign({}, state, {
projects: state.projects.filter(p => p.id !== action.project.id)
});
default:
return state;
}
}
projects.state.ts
import { Project } from '../../../models/Project/Project';
export interface ProjectState {
projects: Project[];
}
Finally my service:
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import {Project} from "../../../models/Project/Project";
@Injectable()
export class ProjectService {
projects: Project[] = [{
id: 1,
title: 'Project Alpha'
}];
constructor() {
}
getAll(): Observable<Project[]> {
return Observable.of(this.projects);
}
}
So what i see on my screen are the 2 initial Projects and not the one project given by the project service. It seems like i do something wrong either in the service or in the reducer or maybe i am completely missing something else.
// UPDATE: I managed to get the effect working. Well at least the effect is called but now i am stuck i an infinit loop. The app won`t response and shows white screen
Maybe someone can help me with that My code in the calling component ist:
import {DELETE_PROJECT, SELECT_ALL_PROJECTS} from '../../store/project.actions';
@Component({
selector: 'project-dashboard',
templateUrl: 'dashboard.component.html',
styleUrls: ['dashboard.component.scss']
})
export class DashboardComponent implements OnInit {
public async: any;
projectState$: Observable<ProjectState>;
constructor(private store: Store<any>) {
// this.store.dispatch({type: SELECT_ALL_PROJECTS});
this.projectState$ = this.store.select<ProjectState>(state => state.projectModule.projectReducer);
}
ngOnInit() {
this.store.dispatch({type: SELECT_ALL_PROJECTS, projects: []});
}
delete(project: Project) {
this.store.dispatch({type: DELETE_PROJECT, project: project})
}
}
Every help is appreciated
Regards