Skip to content

Instantly share code, notes, and snippets.

@pchi
Created January 30, 2016 11:21
Show Gist options
  • Save pchi/5cca83868713c6bd60a6 to your computer and use it in GitHub Desktop.
Save pchi/5cca83868713c6bd60a6 to your computer and use it in GitHub Desktop.
chaining observables with Rx
// watch angular scope $destroy expression and create a kill observable
var controllerScopeIsDestroyed = angularObservableSvc.watchToObservable($scope, '$destroy');
// get datamart status request
var statusObs = dataMartSvc.getSavedState({
userId: $stateParams.id,
refId: $stateParams.ref
});
// get custom views request
var getCustomViewsObs = dataMartSvc.getCustomViews();
// generic service
var service = {
// status = statusObs, views = getCustomViewsObs
setupDMwithCustomViews(status, views) {
var customViews = utilities.mapCdaResponse(views.data);
var viewsCollection = customViews ? [customViews] : [];
var dataMart = _.extend(status, {customViews: viewsCollection});
return dataMart;
}
}
/*
* using zip to mimic concurrency since both responses have same CDA response structure.
* you can pass N number of observables with result selector method as the last argument.
* concatMap ensures order of results with our chained promises
* indentation shows an additional action/observable that is pushed into the sequence
* our sequence blueprint:
*
* zip ( status observable and custom views observable )
* concat datamart preferences observable
* concat get count observable
* stream = [ [status, customViews], [preferences], [count] ]
*
* all the observables are flattened into one event stream which we then subscribe to
* onNext() will be fired when the final result is ready which renders our grid
*/
var getGridDataSequence = Rx.Observable.zip(statusObs, getCustomViewsObs, service.setupDMwithCustomViews)
.concatMap((dataMart) => {
// Compute dataView properties based on profile and search criteria
var dataViewProperties = detailsGridSvc.getViewProperties(dataMart.profile, dataMart.searchCriteria);
// Get mart preferences and count and prepare Kendo grid for loading data
return dataMartSvc.getPreferences(dataMart.properties.tableName, dataMart.profile)
.concatMap((preferences) => {
var dataMartProperties = detailsGridSvc.createFiltersAndSorts(preferences, dataMart, dataViewProperties);
if (customViewsSvc.isCustomView(dataMart.profile)) {
dataMartProperties = customViewsSvc.getIntersectedFiltersAndSorts(dataMartProperties);
}
// Then get total row count
return detailsGridSvc.getCount(dataMartProperties.properties.tableId, dataMartProperties.filters)
.map((filterCount) => {
dataMartProperties.filterCount = filterCount;
return dataMartProperties;
})
.retry(3); // count request is unstable, try 3x
}
})
.takeUntil(controllerScopeIsDestroyed) // kill async sequence when controller is destroyed
.take(1); // just run it once on INIT
getGridDataSequence.subscribe({
onNext(dataMart) {
var dataSource = detailsGridSvc.createKendoGridHybridDataSource(AppSettings.pentaho.queryPath, dataMart);
// send dataMart properties and dataSource to create Grid
detailsGridSvc.createGrid(dataMart, dataSource);
},
onError(err) {
spinnerSvc.stop('spinner-details-container');
},
onCompleted() {
// update scope model to fire digest cycle and show grid
$scope.isReady = true;
}
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment