I am working on an angular2 application which uses ngrx store approach to manage states. App is open source on github here
Problem statement
Specific problem I am facing with this approach is using values emitted from one observable when other observable returns null .
I don't want to query backend api when I have data present in my ngrx store .
Angular2 Code
Below is my trips.reducer.ts
file
export interface State {
ids: string[];
trips: { [id: string]: Trip };
selectedTripId: string;
}
const initialState = {
ids: [],
trips: {},
selectedTripId: null
}
export function reducer(state = initialState, action: Action ): State {}
export function getTrips(state : State) {
return state.trips;
}
export function getTripIds(state: State) {
return state.ids;
}
export function getSelectedTripId(state: State) {
return state.selectedTripId;
}
Below is my base reducer index.ts
export interface State {
trips: fromTripsReducer.State;
}
const reducers = {
trips: fromTripsReducer.reducer,
}
export function getTripsState(state: State): fromTripsReducer.State {
return state.trips;
}
export const getTrips = createSelector(getTripsState, fromTripsReducer.getTrips);
export const getTripIds = createSelector(getTripsState, fromTripsReducer.getTripIds);
export const getSelectedTripId = createSelector(getTripsState, fromTripsReducer.getSelectedTripId);
export const getSelectedCityId = createSelector(getTripsState, fromTripsReducer.getSelectedCityId);
export const getTripsCollection = createSelector(getTrips, getTripIds, (trips, ids) => {
return ids.map(id => trips[id]);
});
export const getSelectedTrip = createSelector(getTrips, getSelectedTripId, (trips, id) => {
return trips[id];
});
Now I can get a particular trip in trip-detail.component.ts
like this
selectedTrip$: Trip;
constructor(private store: Store<fromRoot.State>) {
this.selectedTrip$ = this.store.select(fromRoot.getSelectedTrip);
}
Now if I reload the route localhost:4200/trips/2
, then our store will initialize to initialState that is shown below
const initialState = {
ids: [],
trips: {},
selectedTripId: null
}
and below method will not work as getTrips and getSelectedTripId will be null
export const getSelectedTrip = createSelector(getTrips, getSelectedTripId, (trips, id) => {
return trips[id];
});
So now I can make a backend request which will load only the single trip based on the url id like this
return this.http.get(`${this.apiLink}/trips/${trip_id}.json`
.map((data) => data.json())
But i want to make backend request only when the trip is not present in the store and
this.selectedTrip$ returns null or undefined.
this.selectedTrip$ = this.store.select(fromRoot.getSelectedTrip);
If you need the data to be ready before the component is being shown you could use a resolver. See this answer here .
In your case it would look the following and the resolver would only make sure that the loading of the data is initialized if selectedTrip
is null
. Note: As we won't use the returned data of the resolver anywhere, we can just return anything.
@Injectable()
export class SelectedTripResolver implements Resolve {
constructor(
private store: Store
) {}
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
// get the selectedTrip
return this.store.select(fromRoot.getSelectedTrip)
// check if data is ready. If not trigger loading actions
.map( (selectedTrip) => {
if (selectedTrip === null) {
//trigger action for loading trips & selectedTrip
this.store.dispatch(new LoadTripAction());
this.store.dispatch(new LoadselectedTripAction());
return false; // just return anything
} else {
return true; // just return anything
}
});
}
Here the resolver will make sure that the load actions are triggered when the selectedTrip
data is not ready.
In the trip-detail.component
you'll only need to wait for valid data. Like so:
constructor(private store: Store<fromRoot.State>) {
this.selectedTrip$ = this.store.select(fromRoot.getSelectedTrip)
.filter(selectedTrip => selectedTrip !== null);
}
Hope that makes sense and helps you.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.