store icon indicating copy to clipboard operation
store copied to clipboard

Subscription lost after pushing page with NavController

Open PowerMogli opened this issue 7 years ago • 2 comments

This is a...

  • [ ] feature request
  • [x] bug report
  • [ ] usage question

What toolchain are you using for transpilation/bundling?

  • [ ] @angular/cli
  • [ ] Custom @ngTools/webpack
  • [ ] Raw ngc
  • [ ] SystemJS
  • [ ] Rollup
  • [x] Other (Ionic 3)

Environment

NodeJS Version: 9.3.0 Typescript Version: 2.4.2 Angular Version: 5.0.3 @angular-redux/store version: 7.1.0 @angular/cli version: (if applicable) OS: Windows 10

Expected Behaviour:

Subcriptions should work after moving to an other page and comming back again.

Actual Behaviour:

After pushing from the page with one select decorator @select(['patients', 'items']) to another page without one and then coming back with the back button, our observable does not get fired anymore. All subscriptions stopped working. When we start adding new patients to the state they are not popping up in the ui anymore. All new objects are going through the reducer and the state gets changed properly. But our items$ property does not get updated.

Stack Trace/Error Message:

No.

in patient-list.ts

export class PatientListPage {

@select(['patients', 'items'])
  items$: Observable<IPatient[]>;
}

in store.create.ts

import { compose, createStore } from 'redux';
import { IClientDataSyncService } from '../services/contracts/sync/clientDataSync';
import { IAppState } from './store.model';
import { rootReducer } from './store.reducers';

export const configureStore = (clientDataSync: IClientDataSyncService, preloadedState?: IAppState) => {
  
  return createStore<IAppState>(
    rootReducer,
    preloadedState,
  );
};

in store.module.ts

import { IClientDataSyncService, TYPE } from '../services/contracts/sync/clientDataSync';
import { lazyInject } from '../utils/ioc/ioc';
import { configureStore } from './store.create';
import { IAppState } from './store.model';

@NgModule({
  imports: [NgReduxModule /*NgReduxRouterModule*/],
})
export class StoreModule {
  @lazyInject(TYPE.DataSyncService) private dataSyncService: IClientDataSyncService;

  constructor(private store: NgRedux<IAppState>) {
    store.provideStore(configureStore(this.dataSyncService));

    provideReduxForms(store);
  }
}

in store.reducers.ts

import { composeReducers, defaultFormReducer } from '@angular-redux/form';
import { combineReducers, Reducer } from 'redux';

import { reducer as auditReducer } from '../components/swodoc/_reducers/audit.reducer';
import { reducer as templateReducer } from '../components/swodoc/_reducers/template.reducer';
import { reducer as orderReducer } from '../pages/order/order.reducer';
import { reducer as selectedPatientReducer } from '../pages/patient/patient-edit/edit-patient.reducer';
import { reducer as patientsReducer } from '../pages/patient/patients.reducer';
import { IAppState } from './store.model';

// Define the global store shape by combining our application's
// reducers together into a given structure.
export const rootReducer: Reducer<IAppState> = composeReducers<IAppState>(
  defaultFormReducer(),
  combineReducers({
    patients: patientsReducer,
    orders: orderReducer,
    patientSelection: selectedPatientReducer,
    audits: auditReducer,
    templates: templateReducer,
    // router: routerReducer,
  }),
);

in patient.reducer.ts

import { reducerWithInitialState } from 'typescript-fsa-reducers';

import { IPatient } from '../../models/contracts/patient';
import { createPatient, deletePatient, editPatient } from './patients.actions';
import { IPatientState } from './patients.model';

const initialState: IPatientState = {
  isFetching: false,
  items: [],
};

const createPatientHandler = (state: IPatientState, patient: IPatient): IPatientState => {
  if (state.items.findIndex(x => x._id === patient._id) === -1) {
    return {
      ...state,
      items: [...state.items, patient],
    };
  }

  return state;
};

const editPatientHandler = (state: IPatientState, patient: IPatient): IPatientState => {
  const newstate = {
    ...state,
    items: state.items.map(item => (item._id === patient._id ? { ...item, ...patient } : item)),
  };

  return newstate;
};

const deletePatientHandler = (state: IPatientState, patient: IPatient): IPatientState => {
  const newstate = {
    ...state,
    items: state.items.filter(item => item._id !== patient._id),
  };

  return newstate;
};

export const reducer = reducerWithInitialState(initialState)
  .case(createPatient, createPatientHandler)
  .case(editPatient, editPatientHandler)
  .case(deletePatient, deletePatientHandler);

PowerMogli avatar Jan 23 '18 07:01 PowerMogli

We now know why this is happening. When we use lazy loading for pages with NavController from Ionic like this:

this.navCtrl.push('PatientDetailPage', { item: patient });

then our store module where we instantiate the store is loaded again by angulars bootstrapping process. This is probably a bug in angular 5?

PowerMogli avatar Jan 23 '18 10:01 PowerMogli

Same problem here, with ng4 and ngcli

guilhermejcgois avatar Feb 01 '18 18:02 guilhermejcgois