Use angular ion-refresher (ionic) with ngxs state management (loading status)

Viewed 16

In my angular app I want to use the ion-refresher from ionic to reload my page. The reload is dispatched over a ngxs action.

The html-code of the component:

<ion-refresher slot="fixed" (ionRefresh)="doRefresh($event)">
   <ion-refresher-content></ion-refresher-content>
</ion-refresher>

The doRefresh-method from the component:

 doRefresh(event) {
   this.store.dispatch(new LoadMainData());
   this.loading$.subscribe(loading => {
     if(loading === false) {
       event.target.complete();
     }
   });
 }

This is my ngxs-state:

export interface IncidentStateModel {
 departmentCount: number;
 departmentCountNoe: number;
 departmentCountStmk: number;
 departmentCountOoe: number;
 departmentCountBgld: number;
 incidentCount: number;
 incidentCountNoe: number;
 incidentCountStmk: number;
 incidentCountOoe: number;
 incidentCountBgld: number;
 loading: boolean;
 loadingNoe: boolean;
 loadingStmk: boolean;
 loadingOoe: boolean;
 loadingBgld: boolean;
 incidentsNoe: Incident[];
 incidentsStmk: Incident[];
 incidentsBgld: Incident[];
 incidentsOoe: Incident[];
 routingParamState: string;
}

@State<IncidentStateModel>({
 name: 'incident',
 defaults: {
   departmentCount: 0,
   departmentCountNoe: 0,
   departmentCountStmk: 0,
   departmentCountOoe: 0,
   departmentCountBgld: 0,
   incidentCount: 0,
   incidentCountNoe: 0,
   incidentCountStmk: 0,
   incidentCountOoe: 0,
   incidentCountBgld: 0,
   loading: false,
   loadingNoe: false,
   loadingStmk: false,
   loadingOoe: false,
   loadingBgld: false,
   incidentsNoe: [],
   incidentsStmk: [],
   incidentsBgld: [],
   incidentsOoe: [],
   routingParamState: undefined
 }
})

@Injectable()
export class IncidentState {

 constructor(
   private stmkService: DataStmkService,
   private noeService: DataNoeService,
   private ooeService: DataOoeService,
   private bgldService: DataBgldService
 ) {}

 @Selector()
 static loadingData(state: IncidentStateModel) {
   return state.loading;
 }

 @Selector()
 static routingParamState(state: IncidentStateModel) {
   return state.routingParamState;
 }

 @Selector()
 static incidentsNoe(state: IncidentStateModel) {
   return state.incidentsNoe;
 }

 @Selector()
 static incidentCountNoe(state: IncidentStateModel) {
   return state.incidentCountNoe;
 }

 @Selector()
 static departmentCountNoe(state: IncidentStateModel) {
   return state.departmentCountNoe;
 }

 @Selector()
 static incidentsStmk(state: IncidentStateModel) {
   return state.incidentsStmk;
 }

 @Selector()
 static incidentCountStmk(state: IncidentStateModel) {
   return state.incidentCountStmk;
 }

 @Selector()
 static departmentCountStmk(state: IncidentStateModel) {
   return state.departmentCountStmk;
 }

 @Selector()
 static incidentsOoe(state: IncidentStateModel) {
   return state.incidentsOoe;
 }

 @Selector()
 static incidentCountOoe(state: IncidentStateModel) {
   return state.incidentCountOoe;
 }

 @Selector()
 static departmentCountOoe(state: IncidentStateModel) {
   return state.departmentCountOoe;
 }

 @Selector()
 static incidentsBgld(state: IncidentStateModel) {
   return state.incidentsBgld;
 }

 @Selector()
 static incidentCountBgld(state: IncidentStateModel) {
   return state.incidentCountBgld;
 }

 @Selector()
 static departmentCountBgld(state: IncidentStateModel) {
   return state.departmentCountBgld;
 }

 @Action(LoadMainData)
 loadMainData(ctx: StateContext<IncidentStateModel>, action: LoadMainData) {
   ctx.patchState({ loading: true });
   ctx.dispatch([
      new LoadNoeData(),
      new LoadNoeIncidentData(),
      new LoadStmkData(),
      new LoadOoeData(),
      new LoadBgldData()
   ]);
   ctx.patchState({ loading: false });
 }

 @Action(LoadNoeData)
 loadNoeData(ctx: StateContext<IncidentStateModel>, action: LoadNoeData) {
   ctx.patchState({loadingNoe: true});
   return this.noeService.getMainData()
     .pipe(
       tap((mainData: MainData) => {
         let dpCnoe = 0;
         let idCnoe = 0;
         mainData.Bezirke.forEach((district: District) => {
           dpCnoe += district.f;
           idCnoe += district.e;
         });
         ctx.patchState({
           departmentCountNoe: dpCnoe,
           incidentCountNoe: idCnoe,
           loadingNoe: false
         });
       }),
     );
 }

 @Action(LoadNoeIncidentData)
 loadNoeIncident(ctx: StateContext<IncidentStateModel>, action: LoadNoeData) {
   ctx.patchState({loadingNoe: true});
   return this.noeService.getIncidentData()
     .pipe(
       tap((incidentData: IncidentDataNoe) => {
         const incidents: Incident[] = [];
         incidentData.Einsatz.forEach((incidentNoe: IncidentNoe) => {
           const idt: Incident = {
             title: incidentNoe.a + ' ' + incidentNoe.m,
             location: incidentNoe.o,
             dateTime: incidentNoe.d + ' ' + incidentNoe.t
           };
           incidents.push(idt);
         });
         ctx.patchState({
           incidentsNoe: incidents,
           loadingNoe: false
         });
       }),
     );
 }

 @Action(LoadStmkData)
 loadStmkData(ctx: StateContext<IncidentStateModel>, action: LoadStmkData) {
   ctx.patchState({loadingStmk: true});
   return this.stmkService.getIncidentData()
     .pipe(
       tap((incidentData: IncidentDataStmk) => {
         let dpCstmk = 0;
         const idCstmk = incidentData.features.length;
         const incidents: Incident[] = [];
         incidentData.features.forEach((feature: Feature) => {
           const properties = feature.properties;
           const depCount = Number(properties['Wehren im Einsatz']);
           if(!isNaN(depCount)) {
             dpCstmk += depCount;
           }
           const idt: Incident = {
             title: properties['Typ'] + ' - ' + properties['Art'],
             location: properties['Feuerwehr'],
             dateTime: properties['Datum'] + ' ' + properties['Im Einsatz seit']
           };
           incidents.push(idt);
         });
         ctx.patchState({
           incidentsStmk: incidents,
           departmentCountStmk: dpCstmk,
           incidentCountStmk: idCstmk,
           loadingStmk: false
         });
       })
     );
 }

 @Action(LoadOoeData)
 loadOoeData(ctx: StateContext<IncidentStateModel>, action: LoadStmkData) {
   ctx.patchState({loadingOoe: true});
   return this.ooeService.getIncidentData()
     .pipe(
       tap((incidentData: IncidentDataOoe) => {
         const incidents: Incident[] = [];
         if(incidentData.einsaetze != null) {
           Object.values(incidentData.einsaetze).forEach(val => {
             let startTime = val.einsatz.startzeit.substring(4);
             startTime = startTime.slice(0, -5);
             const idt: Incident = {
               title: val.einsatz.einsatzsubtyp.text,
               location: val.einsatz.einsatzort,
               dateTime: startTime
             };
             incidents.push(idt);
           });
         }
         const dpCooe = incidentData.cnt_feuerwehren;
         const idCooe = incidentData.cnt_einsaetze;
         ctx.patchState({
           incidentsOoe: incidents,
           departmentCountOoe: dpCooe,
           incidentCountOoe: idCooe,
           loadingOoe: false
         });
       })
     );
 }

 @Action(LoadBgldData)
 loadBgldData(ctx: StateContext<IncidentStateModel>, action: LoadStmkData) {
   ctx.patchState({loadingBgld: true});
   return this.bgldService.getIncidentData()
     .pipe(
       tap((incidentData: IncidentDataBgld) => {
         let dpCbgld = 0;
         let idCbgld = 0;
         const incidents: Incident[] = [];
         incidentData.operations_current.forEach((operation: OperationCurrent) => {
           if(operation.code != null && operation.code_desc != null) {
             idCbgld++;
             if(operation.num_fire_services != null) {
               dpCbgld += operation.num_fire_services;
             } else {
               const numStroke = operation.fire_services.split('|').length;
               dpCbgld += numStroke;
             }
             const d = new Date(0);
             d.setUTCSeconds(operation.start);
             const dateString = d.toLocaleDateString('de-DE', { year: 'numeric', month: 'numeric', day: 'numeric'});
             const idt: Incident = {
               title: operation.code + ' - ' + operation.code_desc,
               location: operation.place_of_operation,
               dateTime: dateString + ' ' + d.getHours() + ':' + d.getMinutes()
             };
             incidents.push(idt);
           }
         });
         ctx.patchState({
           incidentsBgld: incidents,
           departmentCountBgld: dpCbgld,
           incidentCountBgld: dpCbgld,
           loadingBgld: false
         });
       })
     );
 }
}

The action is dispatched, but the value of $loading is set to false before loading is complete. I have already tried to modify the loadMainData() action like this: ( As described in https://www.ngxs.io/advanced/actions-life-cycle I dispatched the action with mergeMap())

@Action(LoadMainData)
  loadMainData(ctx: StateContext<IncidentStateModel>, action: LoadMainData) {
    ctx.patchState({ loading: true });
    mergeMap(() =>
      ctx.dispatch([
        new LoadNoeData(),
        new LoadNoeIncidentData(),
        new LoadStmkData(),
        new LoadOoeData(),
        new LoadBgldData()
      ])
    );
    ctx.patchState({ loading: false });
  }

But with this solution, no data is loaded. Does anyone have a solution how I can implement the loading (with ion-refresher and ngxs)?

0 Answers
Related