4
votes

I'm using ngrx/store in my app and I'm having trouble saving an array. My array is set to empty at startup with:

export interface AppState{
    customObjects: Array<CustomObject>;
};

export const initialState: AppState = {
    customObjects: []
};

and I am trying to manually feed it an array of two CustomObjects using the following function:

loadCustomObjects() {
    let initialItems: CustomObject[] = [
        {
            directoryName: "d_name_1",
            brokenLinks: 0,
        },
        {
            directoryName: "d_name_2",
            brokenLinks: 0,
        }
    ];

    this.appStore.dispatch({ type: LOAD_CUSTOM_OBJECTS, payload: initialItems });
}

Calling this function dispatches a call to my reducer function:

export const mainReducer: ActionReducer = (state: AppState, action: Action) => {

if (typeof state == 'undefined') {
    state = initialState;
}

switch (action.type) {
    case LOAD_CUSTOM_OBJECTS:
        return Object.assign({}, action.payload)
    default: {
        return state;
    }
}

}

This all seems fine, but my main app component's array does not get the two objects. If I manually set the default state to have those two CustomObjects, then it works (I can't do this since I need to be able to update the array whenever I want). My HomeComponent uses:

customObjects$ Observable<Array<CustomObject>>;

constructor(private appStore: Store<AppState>) {
            appstore.select('mainReducer')
            .subscribe((data: AppState) => {

                if (typeof data != 'undefined') {
                    this.customObjects$ = Observable.of(data.customObjects);
                }
            });
}

I've analyzed my objects and I expect to see 'this.customObjects$' end up being an array of two CustomObjects. Instead, it is a ScalarOservable:

ScalarObservable {_isScalar: true, value: undefined, scheduler: null}, etc. etc.

Note - I'm not sure if I need to, but I have included ChangeDetectionStrategy.onPush in my home component's @Component section. I've also made sure to use

StoreModule.provideStore({ mainReducer })

in my app.module class.

Does anyone know what I'm doing wrong and why 'this.customObjects$' is not a two object array? I'm new to ngrx/store - I get the feeling there is an issue with the way my reducer function is setting the array but I'm not sure.

1

1 Answers

1
votes

I was able to get it to work with this code:

Store related code:

export interface CustomObject {
  directoryName: string;
  brokenLinks: number;
}

export interface AppState {
  Main: CustomObject[];
};

export function MainReducer(state: CustomObject[] = [], action: Action) {

  switch (action.type) {
    case LOAD_CUSTOM_OBJECTS:
      return Object.assign({}, action.payload);
    default: {
      return state;
    }
  }
}

const reducers = {
  Main: MainReducer
};

Component/Service to dispatch/listen to store

customObjects: CustomObject[];

constructor(private appStore: Store<AppState>) {
  appStore.select(store => store.Main)
    .subscribe(objs => {
      this.customObjects = objs;
      console.log(this.customObjects);
    })
}


loadCustomObjects() {
  let initialItems: CustomObject[] = [
    {
      directoryName: "d_name_1",
      brokenLinks: 0,
    },
    {
      directoryName: "d_name_2",
      brokenLinks: 0,
    }
  ];

  this.appStore.dispatch({ type: LOAD_CUSTOM_OBJECTS, payload: initialItems });
}

Async pipe version:

customObjects$: Observable<CustomObject[]>;

constructor(private appStore: Store<AppState>) {
  this.customObjects$ = appStore.select(store => store.Main);
}


loadCustomObjects() {
  let initialItems: CustomObject[] = [
    {
      directoryName: "d_name_1",
      brokenLinks: 0,
    },
    {
      directoryName: "d_name_2",
      brokenLinks: 0,
    }
  ];

  this.appStore.dispatch({ type: LOAD_CUSTOM_OBJECTS, payload: initialItems });
}

<div *ngFor="let customObj of customObjects$ | async"></div>