A total Redux noob here, I am having a little difficulty getting my data out of the store for use within my view. Here are my Actions, Reducers etc.
genre.model.ts
export interface Genre {
id: string;
title: string;
description: string;
slug: string;
error: string;
}
export const initialState: Genre = {
id: '',
title: '',
description: '',
slug: '',
error: null
};
genre.service.ts
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs/Observable';
import { Http } from '@angular/http';
import {environment} from "../../../environments/environment";
import {Genre} from "./genre.model";
@Injectable()
export class GenreService {
apiUrl = environment.apiUrl + environment.apiVersion + '/';
constructor(private http: Http) { }
/**
* Gets Genres
*
* @returns {Observable<Genre[]>}
*/
getGenres(): Observable<Genre[]> {
return this.http.get(this.apiUrl + 'genres/')
.map(res => res.json());
}
/**
* Gets an individual genre
*
* @param {String} slug
* @returns {Observable<Genre[]>}
*/
getGenre(slug: String): Observable<Genre[]> {
return this.http.get(this.apiUrl + 'genres/' + slug)
.map(res => res.json().genre);
}
}
genre.actions.ts
import { Action } from '@ngrx/store';
import { Injectable } from '@angular/core';
import { Genre } from '../_shared/genre.model';
@Injectable()
export class GenreActions {
static LOAD_GENRES = '[Genre] Load Genres';
loadGenres(): Action {
return {
type: GenreActions.LOAD_GENRES
};
}
static LOAD_GENRES_SUCCESS = '[Genre] Load Genres Success';
loadGenresSuccess(genres): Action {
return {
type: GenreActions.LOAD_GENRES_SUCCESS,
payload: genres
};
}
static GET_GENRE = '[Genre] Get Genre';
getGenre(slug): Action {
return {
type: GenreActions.GET_GENRE,
payload: slug
};
}
static GET_GENRE_SUCCESS = '[Genre] Get Genre Success';
getGenreSuccess(genre): Action {
return {
type: GenreActions.GET_GENRE_SUCCESS,
payload: genre
};
}
}
genre.reducers.ts
import { Action } from '@ngrx/store';
import {Genre, initialState} from '../_shared/genre.model';
import { GenreActions } from './genre.actions';
export function genreReducer(state: Genre = initialState, action: Action) {
switch (action.type) {
case GenreActions.GET_GENRE_SUCCESS: {
return action.payload;
}
case GenreActions.LOAD_GENRES_SUCCESS: {
return action.payload;
}
default: {
return state;
}
}
}
genre.effects.ts
export class GenreEffects {
constructor (
private update$: Actions,
private genreActions: GenreActions,
private svc: GenreService,
) {}
@Effect() loadGenres$ = this.update$
.ofType(GenreActions.LOAD_GENRES)
.switchMap(() => this.svc.getGenres())
.map(genres => this.genreActions.loadGenresSuccess(genres));
@Effect() getGenre$ = this.update$
.ofType(GenreActions.GET_GENRE)
.map(action => action.payload)
.switchMap(slug => this.svc.getGenre(slug))
.map(genre => this.genreActions.getGenreSuccess(genre));
}
genre.detail.component.ts
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs/Observable';
import { Subscription } from 'rxjs/Subscription';
import { ActivatedRoute, Router } from '@angular/router';
import { Component, OnInit } from '@angular/core';
import { Genre } from '../_shared/genre.model';
import { GenreActions } from '../_store/genre.actions';
@Component({
selector: 'app-genre-detail',
templateUrl: './genre-detail.component.html',
styleUrls: ['./genre-detail.component.scss']
})
export class GenreDetailComponent implements OnInit {
public idSub: Subscription;
public genre: Observable<any>;
constructor(
private store: Store<Genre>,
private route: ActivatedRoute,
private genreActions: GenreActions,
private router: Router
) {
this.genre = store.select('genres');
}
ngOnInit() {
this.idSub = this.route.params.subscribe(params => {
this.store.dispatch(this.genreActions.getGenre(params['slug']));
console.log(this.genre);
});
}
}
I can see that my API request is being fired, and it is return data, I can see in the Redux devtools that state is being populated but I just can't seem to get the data out and in to my views using the normal {{ genre.title }} I just get [Object object] being thrown back at me?
I am sure that this might be something really easy but like I said I am a total noob and have spent around 5 hours on this trying out different things following different tutorials etc.

I am guessing your genre is a list of array
It should be some thing like this take it as wireframe.
genre : any ;
ngOnInit(){
this.idSub = this.route.params.subscribe(params => {
this.store.dispatch(this.genreActions.getGenre(params['slug']));
});
this.store.select('genres').subscribe(data => this.genre = data)
}
If you want to look up to ngrx 4 look at this link
I just dug up my git you can check this snapshot of my repo of using ngrx v2 . I donot have a working example for the same but rest assured the code workes LINK
UPDATE
Make a different Object for Genre to use the Genre interface in state
export interface AppState {
genre:Genre
}
Now Subscribe to this state object genre in the constructor or ngOnInit
private store: Store<AppState>,
private route: ActivatedRoute,
private genreActions: GenreActions,
private router: Router
) {
this.store.select('genre').subscribe(data => this.genre = data);
}
Currently, you are getting just the Observable but expecting the list of genre. And, that is the problem. You need to subscribe it to get the value.
Make a different Object for Genre to use the Genre interface in state (as Rahul Singh told already)
export interface AppState {
genre:Genre
}
constructor(private store: Store<AppState>,
private route: ActivatedRoute,
private genreActions: GenreActions,
private router: Router) {}
and in ngOnInit subscribe it to obeserve the change.
ngOnInit(): void {
this.store.select(s => s.genre).subscribe(data => this.genre = data);
}
Note: ngOnInit() is used to make sure that the component's properties (for example: @Input() someId: number) you used are already initialized . So, If you use any component properties you should do it in ngOnInit(). otherwise constructor() is fine.
but we should use constructor() to setup Dependency Injection and not much else. ngOnInit() is better place to "start" - it's where/when components' bindings are resolved.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With