Actually, I'm stuck with a problem with ngxs (3.2.0) state management for my date object. I'm trying to update a display date in my app (Angular 6 app with the angular material), the action is correctly dispatched and the date object is changed within the state but the subscribers don't do anything when the date changed and therefore my template doesn't update.
Here is my action file currentDate.action.ts :
export class CreateDate {
static readonly type = '[app] create date';
constructor(public payload: Date) { }
}
export class ChangeDate {
static readonly type = '[app] change date';
constructor(public payload: Date) { }
}
export class IncrementDate {
static readonly type = '[app] increment date';
constructor() { }
}
export class DecrementDate {
static readonly type = '[app] decrement date';
constructor() { }
}
Here is my currentDate.state.ts :
export interface CurrentDateModel {
selectedDate: Date;
currentDate: Date;
checker: number;
}
@State<CurrentDateModel>({
name: 'currentDate',
defaults: {
currentDate: new Date(),
selectedDate: new Date(),
checker: 0
},
})
export class CurrentDateState {
@Action(CreateDate)
createDate(ctx: StateContext<CurrentDateModel>, { payload }: CreateDate) {
ctx.patchState({ currentDate: payload });
}
@Action(IncrementChecker)
IncrementChecker(ctx: StateContext<CurrentDateModel>) {
const state = ctx.getState();
state.checker = state.checker + 1;
ctx.setState(state);
}
@Action(IncrementDate)
IncrementDate(ctx: StateContext<CurrentDateModel>) {
const state = ctx.getState();
state.selectedDate.setMonth(state.selectedDate.getMonth() + 1);
ctx.setState(state);
}
@Action(DecrementDate)
DecrementDate(ctx: StateContext<CurrentDateModel>) {
const state = ctx.getState();
state.selectedDate.setMonth(state.selectedDate.getMonth() - 1);
ctx.setState(state);
}
@Action(ChangeDate)
changeDate(ctx: StateContext<CurrentDateModel>, { payload }: ChangeDate) {
ctx.patchState({ currentDate: payload });
}
}
The code in my header.ts file :
@Component({
selector: 'app-header',
templateUrl: './header.component.html',
styleUrls: ['./header.component.css']
})
export class HeaderComponent implements OnInit {
@Select(state => state.currentDate.selectedDate) currentDate: Observable<Date>;
@Select(state => state.currentDate.checker) check: Observable<number>;
constructor(private store: Store) { }
ngOnInit() {
this.currentDate.subscribe((date) => console.log('hello from header', date));
this.check.subscribe(() => console.log('i changed'));
}
increment() {
this.store.dispatch(new IncrementChecker());
}
decrementDate() {
this.store.dispatch(new DecrementDate());
}
incrementDate() {
this.store.dispatch(new IncrementDate());
}
}
In my template.html file :
<mat-toolbar color="primary">
<div>
<a mat-button routerLink="">Test</a>
</div>
<div>{{check | async}}</div>
<div><mat-icon (click)="decrementDate()">arrow_left</mat-icon></div>
<div>{{currentDate | async | date:'MMMM' | titlecase}}</div>
<div><mat-icon (click)="incrementDate()">arrow_right</mat-icon></div>
<div fxFlex fxLayout fxLayoutAlign="flex-end">
<button mat-button>Se connecter</button>
</div>
<div><button mat-button (click)="increment()">Increment</button></div>
</mat-toolbar>
I tried many things (this is why you can see the "check" variable in my files too) but did not succeed to see the update with the date object but succeed to another object like my checker here or my others state objects.
If you have any idea or if you see a big mistake in my code...
In your actions:
@Action(IncrementDate)
IncrementDate(ctx: StateContext<CurrentDateModel>) {
const state = ctx.getState();
state.selectedDate.setMonth(state.selectedDate.getMonth() + 1);
ctx.setState(state);
}
You should be updating the state as follows:
let tmpDate = state.selectedDate;
ctx.setState({...state, selectedDate: tmpDate.setMonth(tmpDate.getMonth() + 1});
see: ngxs state
alternatively you could use patchState instead of setState: patchState vs setState