I have a blog application and I'm using ngrx.
the application -for now- have two objects in the store
{
"posts": [...],
"users": [...]
}
now I want to make a separated component to show a single post (selected-post.component).
I tried to select the entity by its id using a selector like this:
export const selectPostById = (id: string) => createSelector(
selectEntities,
entities => entities[id]
);
and then get it in the component:
postId: string = localStorage.getItem("_selectedPostId");
selectedPost: Observable<Post> = this.store.select(selectPostById(postId));
then to show it in the view I used:
<ng-container *ngIf="selectedPost | async">
<div class="post text-light">
<div class="p-title fs-3">{{(selectedPost | async).title}}</div>
<div class="p-image">
<img [src]="(selectedPost | async).imageSrc">
</div>
<div class="p-cont fs-5">
{{(selectedPost | async).content}}
</div>
<div class="p-category float-start fs-6">
<a class="p-1" href="categories/category" *ngFor="let ct of (selectedPost | async).categories">
{{ct}}
</a>
</div>
<div class="p-date float-end fs-6">
{{(selectedPost | async).date}}
</div>
<div class="p-author fs-6">
<a href="users/otheruser">{{(selectedPost | async).author.name}}</a>
</div>
</div>
<div class="info">Comments</div>
<div class="comments text-light">
<div class="comment border rounded m-1" *ngFor="let comment of (selectedPost | async).comments">
<div class="c-author">
<a href="users/otheruser">{{comment.author.name}}</a>
</div>
<div class="c-cont">{{comment.content}}</div>
<div class="-c-date">{{comment.date}}</div>
<div class="replies" *ngIf="comment.replies">
<div class="comment border rounded m-1" *ngFor="let reply of comment.replies">
<div class="c-author">
<a href="users/otheruser">{{reply.author.name}}</a>
</div>
<div class="c-cont">{{reply.content}}</div>
<div class="c-date">{{reply.date}}</div>
</div>
</div>
</div>
</div>
</ng-container>
So the problem is that the post is not shown with error in console:
ERROR TypeError: Cannot read properties of undefined (reading: '1')
I selected the post with the id "1" and it exists in the state shown by redux devtools.
Any ideas?.
EDIT: the reducer:
import { Action, createFeatureSelector, createReducer, createSelector, on } from '@ngrx/store';
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import * as postActions from './actions';
import { Post } from 'src/app/models/post';
export interface PostState extends EntityState<Post> {
error: any;
selectedPostId: string | null;
}
export function selectUserId(a: Post): string {
return a.id;
}
export const adapter: EntityAdapter<Post> = createEntityAdapter<Post>({
selectId: selectUserId,
sortComparer: false
});
export const initialState = adapter.getInitialState({error: null,selectedPostId: null});
const testsReducer = createReducer(
initialState,
on(postActions.loadPostsSuccess, (state, {posts}) => adapter.setAll(posts, state)),
on(postActions.loadPostsFailed, (state, {error}) => ({...state, error})),
on(postActions.setSelectedPostId, (state, {id}) => ({...state, selectedPostId: id}))
);
export function reducer(state: PostState, action: Action) {
return testsReducer(state, action);
}
// Selectors
const {
selectIds,
selectEntities,
selectAll,
selectTotal,
} = adapter.getSelectors();
const feature = createFeatureSelector<PostState>('posts');
export const getPosts = createSelector(feature,selectAll);
export const getSelectedPostId = (state: PostState) => state.selectedPostId;
export const selectPostId = createSelector(
feature,
getSelectedPostId
);
export const selectPostById = (id: string) => createSelector(
selectEntities,
entities => entities[id]
);