Reputation: 4072
I have equivalent data types stored on 2 different databases.
Both types of data will be stored in my ngrx store Application State as well as a Merged State.
export interface ApplicationState {
allSQLFoodData: FoodData;
allUserFoodData: FoodData;
mergedFoodData: FoodData;
}
What I need to do, is to get the allSQLFoodData
and the allUserFoodData
from the backends, store those value to the state and also merge both sets of data in the merged state.
I'm doing this by dispatch()
ing an action INITIALIZE_DATA_ACTION
which I then listen for in an effect service.
Here is where I stand in my effect service:
initialize-data-effect-service.ts
@Injectable()
export class InitializeDataEffectService {
@Effect() initialize$: Observable<Action> = this.actions$
.ofType(INITIALIZE_DATA_ACTION)
.switchMap( (action) => {
return Observable.combineLatest(
this.foodService.loadSQLFoods( action.payload ),
this.userDataService.loadUserData( action.payload )
)
})
.switchMap(([allSQLFoodData, allUserData]) => {
return Observable.of(
new SQLFoodsLoadedAction( allSQLFoodData ),
new UserDataLoadedAction( allUserData ),
new BuildMergedFoodDataAction({sql: allSQLFoodData, user: allUserData})
)
})
constructor( private actions$: Actions, private foodService: FoodService, private userDataService: UserDataService ) {
}
}
As you can see, I am listening for the action of type INITIALIZE_DATA_ACTION
and creating a combined observable using combineLatest()
from the http
responses. I then invoking the Action classes to set the Application state for each:
.switchMap(([allSQLFoodData, allUserData]) => {
return Observable.of(
new SQLFoodsLoadedAction( allSQLFoodData ),
new UserDataLoadedAction( allUserData ),
new BuildMergedFoodDataAction({sql: allSQLFoodData, user: allUserData})
)
})
But this is giving the following error:
The type argument for type parameter 'T' cannot be inferred from the usage. Consider specifying the type arguments explicitly. Type argument candidate 'SQLFoodsLoadedAction' is not a valid type argument because it is not a supertype of candidate 'UserDataLoadedAction'. Types of property 'payload' are incompatible. Type 'AllUserData' is not assignable to type 'AllSQLFoodData'. Property 'foods' is missing in type 'AllUserData'.
I'm not sure how to
specifying the type arguments explicitly
and even if I did, I'm not sure how the Effect()
decorator will now how to assign the results to the appropriate state values. how can I achieve this?
Upvotes: 1
Views: 231
Reputation: 58430
To return an observable from switchMap
that emits multiple actions from the effect, use Observable.from
, which can take an array:
import 'rxjs/add/observable/from';
import 'rxjs/add/operator/concatMap';
...
.concatMap(([allSQLFoodData, allUserData]) => Observable.from([
new SQLFoodsLoadedAction( allSQLFoodData ),
new UserDataLoadedAction( allUserData ),
new BuildMergedFoodDataAction({sql: allSQLFoodData, user: allUserData})
]))
Note that the switchMap
is unecessary, as the returned observable will emit immediately. You can just use concatMap
, instead.
Also, the effect doesn't assign anything to the state. Its only role is to emit actions. Those actions will be handled by reducers that will update the appropriate parts of the application's state.
Upvotes: 3