I am creating a small app in Angular6 which is using @NGRX for state management and Nomalizr to for de/normalization of the data. The normalization happens in an effect and my denormalization needs to happen in a selector.
I am having an issue understanding what to do when attempting to denormalize my state in the selector and am having issues getting it to work.
Here is my code:
My actions:
import {Action} from "@ngrx/store";
export const GET_ARTICLE = 'Get_Article';
export const GET_ARTICLE_LOAD_SUCCESS = 'Get_Article_Load_Success';
export class GetArticleAction implements Action {
readonly type = GET_ARTICLE;
constructor(public payload: string) {}
}
export class GetArticleLoadSuccess implements Action {
readonly type = GET_ARTICLE_LOAD_SUCCESS;
constructor(public payload) {}
}
export type All = GetArticleAction | GetArticleLoadSuccess;
My component code that fires the action and also the subscription to the observable which will watch for state changes:
ngOnInit() {
this.store.pipe(
select(getArticles)
).subscribe((response) => {
console.log(response);
})
}
getArticle(id: string) {
this.store.dispatch(new GetArticleAction(id));
}
}
My effect:
@Effect()
public getArticle$: Observable<Action> = this.actions$.pipe(
ofType(GET_ARTICLE),
switchMap((action: GetArticleAction) => {
// we don't user the action payload here as we are mocking the API call
return of(mockData)
}),
switchMap((response: IArticle) => {
const normalizedData = normalize(response, article);
return of(normalizedData);
}),
flatMap((normalizedData) => [
new GetArticleLoadSuccess(normalizedData)
])
)
And my reducer:
const initialState: ArticleState = {
articles: [],
comments: [],
users: []
};
export function reducer(state = initialState, action: fromActions.All): ArticleState {
switch (action.type) {
case fromActions.GET_ARTICLE: {
return Object.assign({}, state);
}
case fromActions.GET_ARTICLE_LOAD_SUCCESS: {
return Object.assign({}, action.payload);
}
default: {
return state;
}
}
}
export const getArticleState = createFeatureSelector<ArticleState>('articleState');
export const getArticles = createSelector(getArticleState, (state: ArticleState) => {
return denormalize([], article, state.entities);
});
My data is as follows:
import {IArticle} from "./article";
export const mockData: IArticle = {
"id": "123",
"author": {
"id": "1",
"name": "Paul"
},
"title": "My awesome blog post",
"comments": [
{
"id": "324",
"commenter": {
"id": "2",
"name": "Nicole"
}
}
]
};
I can get the normaliaztion working as when I check my store the state object looks as follows:
{
articleState: {
entities: {
users: {
'1': {
id: '1',
name: 'Paul'
},
'2': {
id: '2',
name: 'Nicole'
}
},
comments: {
'324': {
id: '324',
commenter: '2'
}
},
articles: {
'123': {
id: '123',
author: '1',
title: 'My awesome blog post',
comments: [
'324'
]
}
}
},
result: '123'
}
}
As you can see, I created a selector that will return the denormalized state but I am at a loss as to what I need to provide to this function. I have checked the Normalizr docs and I can't seem to understand what needs to be done. Can anyone see maybe where I am going wrong here or how I implement the denormalztion function in the selector to return the denormalized data back to the component? Thanks