I seem to have gotten stuck on this matter for the last couple of days.
We're working on an Angular 2 application, and I need to create a wizard for users to fill out a form.
I've successfully managed to make the data flow through each step of the wizard, and save it in order to freely move back and forth. However, I can't seem to be able to reset it once the form is submitted.
I should add that each component is behind a wall. Maybe a better solution would be a singleton service injected directly at the AppModule. But I can't seem to make it work.
Here's my code so far:
Step 1
import { Component, OnInit } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { EventOption } from '../../../events/shared/event-option.model';
import { Store } from '@ngrx/store';
import { NewEventService } from '../shared/new-event.service';
import { Event } from '../../../events/shared/event.model';
import { FriendService } from '../../../friends/shared/friend.service';
@Component({
selector: 'app-upload-images',
templateUrl: './upload-images.component.html',
styleUrls: ['../../../events/new-event/new-event.component.css']
})
export class UploadImagesComponent implements OnInit {
form: FormGroup;
private event;
private images = [];
constructor(
private _store: Store<any>,
private formBuilder: FormBuilder,
private router: Router,
private newEventService: NewEventService,
private friendService: FriendService
) {
_store.select('newEvent').subscribe(newEvent => {
this.event = newEvent;
})
}
ngOnInit() {
this.initForm(this.event);
if (this.event.counter === 0) {
let friends = this.friendService.getFriends('58aaf6304fabf427e0acc08d');
for (let friend in friends) {
this.event.userIds.push(friends[friend]['id']);
}
}
}
initForm(event: Event) {
this.images.push({ imageUrl: 'test0', voteCount: 0 });
this.images.push({ imageUrl: 'test1', voteCount: 0 });
this.images.push({ imageUrl: 'test2', voteCount: 0 });
this.images.push({ imageUrl: 'test3', voteCount: 0 });
this.form = this.formBuilder.group({
firstImage: [this.event.length > 0 ? this.event.eventOption[0].imageUrl : null],
secondImage: [this.event.length > 0 ? this.event.eventOption[1].imageUrl : null],
thirdImage: [this.event.length > 0 ? this.event.eventOption[2].imageUrl : null],
fourthImage: [this.event.length > 0 ? this.event.eventOption[3].imageUrl : null],
})
}
next() {
this.event.eventOptions = this.images;
this.newEventService.updateEvent(this.event);
this.router.navigate(['events/new-event/choose-friends']);
}
}
Step 2
import { Component, OnInit, Input } from '@angular/core';
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
import { Router } from '@angular/router';
import { EventOption } from '../../../events/shared/event-option.model';
import { Store } from '@ngrx/store';
import { Event } from '../../shared/event.model';
import { NewEventService } from '../shared/new-event.service';
import { FriendService } from '../../../friends/shared/friend.service';
import { SearchPipe } from '../../../core/search.pipe';
@Component({
selector: 'app-choose-friends',
templateUrl: './choose-friends.component.html',
styleUrls: ['../../../events/new-event/new-event.component.css', './choose-friends.component.css']
})
export class ChooseFriendsComponent implements OnInit {
private searchTerm = '';
private event;
private friends = [];
private friendsError = false;
constructor(
private _store: Store<any>,
private formBuilder: FormBuilder,
private router: Router,
private newEventService: NewEventService,
private friendService: FriendService
) {
_store.select('newEvent').subscribe(newEvent => {
this.event = newEvent;
})
}
ngOnInit() {
this.friends = this.friendService.getFriends('58aaf6304fabf427e0acc08d');
}
selectedFriend(friendId: string) {
return this.friendService.selectedFriend(friendId, this.event.userIds);
}
toggleFriend(friendId: string) {
return this.friendService.toggleFriend(friendId, this.event.userIds);
}
toggleAllFriends() {
return this.friendService.toggleAllFriends(this.friends, this.event.userIds);
}
submit() {
if (this.event.userIds.length > 0) {
this.newEventService.resetEvent();
this.router.navigate(['events/vote-events']);
} else {
this.friendsError = true;
}
}
back() {
this.newEventService.updateEvent(this.event);
this.router.navigate(['events/new-event/upload-images']);
}
}
Event Service
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Store, Action } from '@ngrx/store';
import { Event } from '../../../events/shared/event.model';
import { EventOption } from '../../../events/shared/event-option.model';
import { newEvent, newEventModel } from './new-event.reducer';
import 'rxjs/add/operator/take';
import 'rxjs/add/operator/find';
import { Subject } from 'rxjs/Subject';
@Injectable()
export class NewEventService {
public newEvent$: Observable<newEventModel>;
constructor(private store: Store<newEventModel>) {
this.newEvent$ = this.store.select('newEvent');
}
getEvent(event) {
return this.store.dispatch({
type: 'GET_EVENT',
payload: event
})
}
updateEvent(event) {
return this.store.dispatch({
type: 'UPDATE_EVENT',
payload: event
})
}
resetEvent() {
return this.store.dispatch({
type: 'RESET_EVENT',
})
}
}
Event Reducer
import { EventOption } from '../../shared/event-option.model';
import { EventType } from '../../shared/event-type.model';
import { ActionReducer, Action } from '@ngrx/store';
import { Event } from '../../shared/event.model';
import { FriendService } from '../../../friends/shared/friend.service';
export interface newEventModel {
eventOptions: EventOption[];
eventTypeId: number,
duration: number,
comment: string,
privacyId: number,
isGlobal: boolean,
id: string,
userIds: string[],
counter: number
}
let blankState: newEventModel = {
eventOptions: [],
eventTypeId: null,
duration: 1440,
comment: '',
privacyId: 0,
isGlobal: false,
id: '',
userIds: [],
counter: 0
}
let initialState: newEventModel = {
eventOptions: [],
eventTypeId: null,
duration: 1440,
comment: '',
privacyId: 0,
isGlobal: false,
id: '',
userIds: [],
counter: 0
}
export const newEvent: ActionReducer<newEventModel> = (state: newEventModel = initialState, action: Action) => {
// return new state
switch (action.type) {
case 'GET_EVENT':
return state;
case 'UPDATE_EVENT':
action.payload.counter = action.payload.counter + 1;
return action.payload;
case 'RESET_EVENT':
return Object.assign({}, state, {
eventOptions: [],
eventTypeId: null,
duration: 1440,
comment: '',
privacyId: 0,
isGlobal: false,
id: '',
userIds: [],
counter: 0
});
default:
return state;
}
}
I could provide a working plunkr if needed, but I need to create it first.
TLDR: How can I reset the state on @ngrx/store?
Thanks for any help provided!
You can reset the state to initialState
in your reducer by using Object.assign
to copy all properties of initialState
to a new object.
export const newEvent: ActionReducer<newEventModel> = (state: newEventModel = initialState, action: Action) => {
// return new state
switch (action.type) {
// ...
case 'RESET_EVENT':
return Object.assign({}, initialState);
// ...
}
}
The reducer should be a pure function, so should not modify the arguments. Your UPDATE_EVENT
requires a little tweak:
case 'UPDATE_EVENT':
let counter = { counter: action.payload.counter + 1 };
return Object.assign({}, action.payload, counter);
The pattern to follow is Object.assign({}, source1, source2, ...)
where source1
, source2
etc contain properties to be assigned. Properties in source1
are overwritten by duplicate properties in source2
etc.