1
votes

I got pretty simple feature module with store/reducers/etc created by @ngrx/schematics. In this feature module i got 2 components - form and items list which is empty by default and u can add items via form. When i add something via form action works, reducer get payload but items list in second component doesn't update.

items list html:

<section class="sub-list">
  <div class="container">
    <header class="sub-list--header"><h1>My Subscriptions</h1></header>
    <span *ngIf="length$ | async">Subscriptions count - {{ length$ | async }}</span>
    <main class="sub-list--content" *ngIf="list$ | async as list">
      <div class="sub-list--item" *ngFor="let item of list">
        <div class="name">{{ item.name }}</div>
      </div>
    </main>
  </div>
</section>

items list component:

import { Component, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Store } from '@ngrx/store';
import { Observable } from 'rxjs';

// Store
import * as fromSub from '../../reducers/subscription.reducer';
import * as subActions from '../../actions/subscription.actions';
// Models
import { Subscription } from '../../models/Subscription';

@Component({
  selector: 'app-sub-list',
  templateUrl: './sub-list.component.html',
  styleUrls: ['./sub-list.component.scss']
})
export class SubListComponent implements OnInit {
  list$: Observable<Subscription[]>;
  length$: Observable<number>;
  constructor(
    private snackBar: MatSnackBar,
    private subStore: Store<fromSub.State>
  ) {
    this.list$ = this.subStore.select('subscriptionsList');
    this.length$ = this.subStore.select('length');
  }

  ngOnInit() {
  }

}

form component(just in case i did action dispatch wrong):

import { Component, OnInit } from '@angular/core';
import { MatSnackBar } from '@angular/material';
import { Store } from '@ngrx/store';

// Store
import * as fromSub from '../../reducers/subscription.reducer';
import * as subActions from '../../actions/subscription.actions';
// Models
import { Subscription } from '../../models/Subscription';

@Component({
  selector: 'app-sub-form',
  templateUrl: './sub-form.component.html',
  styleUrls: ['./sub-form.component.scss']
})
export class SubFormComponent implements OnInit {
  name: string;
  price: number;
  link: string;
  date: Date;
  constructor(
    private snackBar: MatSnackBar,
    private subStore: Store<fromSub.State>
  ) {
    this.price = 0;
  }

  ngOnInit() {
  }

  addSubscription = (): void => {
    // Snackbar test
    if (!this.name) {
      this.snackBar.open('Name field is empty', 'Close', { duration: 3000 });
      return;
    }
    // if (this.link === '') {}
    if (this.price < 0) {
      return;
    }
    if (!this.date) {
      this.snackBar.open('Date field is empty', 'Close', { duration: 3000 });
      return;
    }
    const newSub: Subscription = {
      name: this.name,
      price: this.price,
      link: this.link,
      date: this.date,
    };
    this.subStore.dispatch(new subActions.AddSubscription(newSub));
    this.snackBar.open('Subscription added', 'Close', { duration: 3000 });
  }
}

module reducer:

import { SubscriptionActions, SubscriptionActionTypes } from '../actions/subscription.actions';
import { Subscription } from '../models/Subscription';

export interface State {
  length: number;
  subscriptionsList: Subscription[];
}

export const initialState: State = {
  length: 0,
  subscriptionsList: [],
};

export function reducer(state = initialState, action: SubscriptionActions): State {
  switch (action.type) {

    case SubscriptionActionTypes.LoadSubscriptions:
      return state;

    case SubscriptionActionTypes.AddSubscription:
      return Object.assign({}, state, {
        subscriptionsList: state.subscriptionsList.concat(action.payload),
        length: state.subscriptionsList.length + 1
      });

    default:
      return state;
  }
}

So it might be the problem in reducer(wrong store update) or in component(wrong select or wrong provider)

1
is your hole state { subscriptionsList: Array, lenght: number }, you don;t have any features in rootStore?Przemyslaw Jan Beigert
@PrzemyslawPietrzak yes, this app is like simple todo list on which i am learning basics of angular and ngrx. So basically i have a list of items and form to fill this list.Иван Брагин
Ok, please paste part of code where you connecting your reducer with angular modulePrzemyslaw Jan Beigert
@PrzemyslawPietrzak ok so here is my module: import * as fromSubscription from './reducers/subscription.reducer'; import { EffectsModule } from '@ngrx/effects'; import { SubscriptionEffects } from './effects/subscription.effects'; @NgModule({ declarations: [SubFormComponent, SubListComponent], imports: [ CommonModule, FormsModule, MaterialModule, StoreModule.forFeature('subscription', fromSubscription.reducer), EffectsModule.forFeature([SubscriptionEffects]), ], exports: [ SubFormComponent, SubListComponent, ]Иван Брагин

1 Answers

0
votes

First thinks first:

Your global store looks like this:

interface RootStore {
  subscription: {
    subscriptionsList: Array<...>,
    length: number;
  }
}

So when you want go get this.lenght$ in component you have to do this:

this.lenght$ = this.store.select(rootStore => rootStore.subscription.lenght)

When you subscribe to store in component you try to get length key on RootStore. It's doesn't exist so you're subscribing to undefined. After dispatch action it's still undefined so you component didn't refresh data.