Tom
Tom

Reputation: 795

Can't make @ngrx/store works properly

I have this Angular 2 app that works. I'm trying to add @ngrx/store to the app but It seem that I can't make it work. Here is what I have to far :

product.component.ts

import {Component, Input, ChangeDetectionStrategy} from "@angular/core";

import {ProductService} from "../index";

declare const module;

@Component({
    selector: 'products',
    moduleId: module.id,
    providers: [ProductService],
    templateUrl: '_products.component.html',
    styleUrls: ['_products.component.css'],
    changeDetection: ChangeDetectionStrategy.OnPush
})
export class _ProductsComponent {

    products;

    constructor(private productService: ProductService) {
        this.products = this.productService.products$;
        this.productService.loadProducts();
    }

}

product.reducer.ts

import {ActionReducer, Action} from '@ngrx/store';
import {Product} from "./index";

export const products: ActionReducer<Product> = (state: any = {}, action:Action) => {
    switch (action.type) {
        case 'ADD_PRODUCTS':
            return action.payload;

        default:
            return state;
    }
}

product.service.ts

import {Injectable} from "@angular/core";

import {HttpService} from "../shared/services/http.service";
import {Store} from "@ngrx/store";
import {AppStore} from "../shared/store.interface";

@Injectable()
export class ProductService {

    products$;

    constructor(
        private store: Store<AppStore>,
        private httpService: HttpService) {
        this.products$ = store.select('products');
    }

    loadProducts() {
        return this.httpService.call('get', 'home')
            .map(res => res.json())
            .map(payload => ({ type: 'ADD_PRODUCTS', payload }))
            .subscribe(action => this.store.dispatch(action))
    }

}

<div class="grid_products">
    {{products | async}} // shows: [object Object],[object Object],[object Object],[object Object]....
    <product*ngFor="let product of products | async" [product]="product" class="grid_product alcenter"></product> // gives me errors
</div>

I feel like I'm almost there because {{products | async}} shows me results. I just don't get the error that *ngFor grives me :

ORIGINAL EXCEPTION: Cannot find a differ supporting object '[object Object]' of type 'object'. NgFor only supports binding to Iterables such as Arrays.

I mean I do understand what it means, but I have no idea why I get this. I feel like I have exactly what the tutos shows...

Links I've used:

Unfortunatly, almost everything is outdated (not RC5).

UPDATE: I juste realise that if I do {{products | async | json}} in my html file, I get all datas. So it's working, I juste dont get why I get this error with the *ngFor.

Upvotes: 2

Views: 928

Answers (2)

KnowHoper
KnowHoper

Reputation: 4622

Change your reducer to this:

import {ActionReducer, Action} from '@ngrx/store';
import {Product} from "./index";

export const products: ActionReducer<Product[]> = (state: Product[] = [], action:Action) => {
    switch (action.type) {

        case 'ADD_PRODUCTS':
          state.push(action.payload);
          return state;

        default:
            return state;
    }
}

Upvotes: 0

wiredprogrammer
wiredprogrammer

Reputation: 555

On your reducer you need to initialize the state to an array and not a object.

Right now you have

state: any = {}

Make it

state: any = []

When the template tries to render the html initially it is trying to iterate the initial state of "products" which is a object and not an array.

Upvotes: 0

Related Questions