I spent the last 2 days with a problem while trying to get a local json data (posts) to show it in the view (PostsComponent). in the console i get this error:
ERROR Error: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.
but i think its not an object, i'm trying to return it as an array.
and another thing, when i try to log the result it is shown like this: { posts: [] }
so it is an object contains an empty array.
i'm inside a module called BaseModule.
here is the shape of the post and the BaseModule state:
export interface BaseState {
posts: Post[];
}
export class Post {
id: number;
title: string;
content: string;
imageSrc: string;
author: {name: string, account: string, imageSrc: string};
date: string;
categories: string[];
}
I created posts.actions.ts file:
import { createAction, props } from "@ngrx/store";
import { Post } from "src/app/types";
export const getAllPosts = createAction('[PostsComponent] Load Posts');
export const getAllPostsSuccessed = createAction(
'[[PostsComponent] Load Posts Successed',
props<{posts: Post[]}>()
);
export const getAllPostsError = createAction(
'[PostsComponent] Load Posts Error',
props<{error: any}>()
);
then the posts.reducer.ts file:
import { createReducer, on } from "@ngrx/store";
import * as postsActions from "./posts.actions";
import { BaseState } from "src/app/types";
const initialState: BaseState = {
posts: []
}
const _postsReducer = createReducer(
initialState,
on(postsActions.getAllPosts, state => state),
on(postsActions.getAllPostsSuccessed, (state, { posts }) => {
console.log(posts); return {...state, posts: posts};
}),
on(postsActions.getAllPostsError, (state, { error }) => { console.log(error); return state})
);
export function postsReducer(state: any, action: any){
return _postsReducer(state, action);
}
and the posts.selectors.ts file:
import { createFeatureSelector, createSelector } from "@ngrx/store";
import { BaseState } from "src/app/types";
const selectBase = createFeatureSelector<BaseState>('base');
export const posts = createSelector(
selectBase,
(state: BaseState) => state.posts
);
then finally the posts.effects.ts file:
import { Actions, createEffect, ofType } from "@ngrx/effects";
import { HttpClient } from "@angular/common/http";
import { catchError, map, mergeMap } from "rxjs/operators";
import { Post } from "src/app/types";
import { Injectable } from "@angular/core";
import { of } from "rxjs";
@Injectable()
export class PostsEffects {
getPosts = createEffect(() => this.actions.pipe(
ofType('[PostsComponent] Load Posts'),
mergeMap(() => this.http.get<{posts: Post[]}>('assets/posts.json').pipe(
map(posts => ({type: '[PostsComponent] Load Posts Successed', posts: posts})),
catchError(error => of({type: '[PostsComponent] Load Posts Error', error: error}))
))
));
constructor(
private http: HttpClient,
private actions: Actions
) { }
}
and this is the posts.component.ts file:
import { Component, OnInit } from "@angular/core";
import { Store } from "@ngrx/store";
import { BaseState, Post } from "src/app/types";
import { getAllPosts } from "./state/posts.actions";
import { posts } from "./state/posts.selector";
@Component({
selector: 'app-posts',
templateUrl: './posts.component.html',
styleUrls: ['./posts.component.scss']
})
export class PostsComponent implements OnInit {
posts: Post[];
limit = 6;
constructor(private store: Store<BaseState>) { }
ngOnInit(): void {
this.store.dispatch(getAllPosts());
this.store.select(posts).subscribe(posts => this.posts = posts);
console.log(this.posts);
}
get getPosts(){
return this.posts;
}
showMore(){
this.limit = this.limit + 6;
}
}
and the posts.component.html file:
<div class="post" *ngFor="let post of getPosts">
<div class="title"><a [routerLink]="'/post/' + post.id.toString()">{{ post.title }}</a></div>
<div class="content">
{{ post.content | slice:0:30 }}<a [routerLink]="'/post/' + post.id.toString()">...Read more</a>
</div>
<div class="image">
<img [src]="post.imageSrc">
</div>
<div class="author" routerLink="#">
<img [src]="post.author.imageSrc">
{{ post.author.name }}
</div>
<div class="date">{{ post.date }}</div>
<div class="categories">
<div class="category" *ngFor="let category of post.categories">
{{ category }}
</div>
</div>
</div>
<div class="show-more" (click)="showMore()">Show More</div>
i'm new to angular and ngrx so please make the answers clear for a beginner.
Here were the problem was:
first:
there was a character "[" added by mistake in the actions file:
'[[PostsComponent] Load Posts Successed'
second:
the json data was made in a wrong type like: {posts: [...]}