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)?