Achieving Reasonable and Scalable Routing in AngularJS with Flux

app.factory('api', function() {
return {
searchAlreadyLoaded: false,
search: function(query) {
// send the query to the server
// return a promise
},
getSearch: function(id) {
// ask server for an existing search
// return a promise
}
}
});
api.search(scope.query).then(function () {
api.searchAlreadyLoaded = true;
$state.go('search', { id: api.id });
api.searchAlreadyLoaded = false;
});
$stateProvider.$state('search', {
url: '/search/:id',
template: '<search />',
resolve: {
function(api, $stateParams) {
if (!api.searchAlreadyLoaded) {
return api.getSearch($stateParams.id);
}
}
}
});
loadingIndicator.show();
api.search(scope.query).then(function () {
loadingIndicator.hide();
api.searchAlreadyLoaded = true;
$state.go('search', { id: api.id });
api.searchAlreadyLoaded = false;
});
$stateProvider.$state('search', {
url: '/search/:id',
template: '<search />',
resolve: {
function(api, $stateParams) {
if (!api.searchAlreadyLoaded) {
var promise = api.getSearch($stateParams.id);
loadingIndicator.show();
promise.then(loadingIndicator.hide);
}
}
}
});
function search(payload) {
if (payload.query) { // new search
dispatcher.dispatch('loadingIndicator:show');
api.search(payload.query).then(function (data) {
dispatcher.dispatch('search:loaded', data);
dispatcher.dispatch('route', {state:'search', id:data.id});
dispatcher.dispatch('loadingIndicator:hide');
});
} else if (payload.id) { // existing search
dispatcher.dispatch('loadingIndicator:show');
api.getSearch(payload.id).then(function (data) {
dispatcher.dispatch('search:loaded', data);
dispatcher.dispatch('route', {state:'search', id:data.id});
dispatcher.dispatch('loadingIndicator:hide');
});
}
}

Adding Routing to the Color Picker

The full source code is in the angular-flux-routing-example repo.

$rootScope.$watch(function() {
return routeStore.path;
}, function (newPath, oldPath) {
$location.path(newPath);
});
$rootScope.$watch(function() {
return $location.path();
}, function(newPath, oldPath) {
if (!routeStore.pathChangedInternally)
actionCreator.routingPathChange({
newPath:newPath,
oldPath:oldPath
});
});
goto: function(payload) {
this.route(payload, true);
},
routingPathChange: function(payload) {
this.route(payload, false)
}
route: function(payload, isInternal) {
payload.pathChangedInternally = isInternal;
payload.route = routeStore.getRouteFromPath(payload.path);

if (payload.route) {
var routeName = payload.route.name;

if (this[routeName]
&& this[routeName](payload.route) !== false) {
dispatcher.dispatch('route', payload);
}
}
},
// navigate to home
home: function(route) {
if (! colorStore.colorsLoaded) {
dispatcher.dispatch('loadingIndicator:show');
colorApi.fetch().success(function(data) {
dispatcher.dispatch('loaded:colors', {colors: data});
dispatcher.dispatch('route', {route:route});
dispatcher.dispatch('loadingIndicator:hide');
});

return false;
}
},

// navigate to about
about: function(route) {
dispatcher.dispatch('loadingIndicator:show');

aboutApi.fetch().success(function(data) {
dispatcher.dispatch('loaded:about', {people: data});
dispatcher.dispatch('route', {route:route});
dispatcher.dispatch('loadingIndicator:hide');
});

return false;
},

Note that when we say that a Store manages state we are really just talking about data. How that data effects the visual appearance of the application is not the direct responsibility of the Store. For example, the appStore object might have a theme property with a corresponding string value. This data stored in the appStore relates directly to some part of the UI, but the appStore isn’t responsible for the rendering of the UI.

$rootScope.$watch(function() {
return routeStore.currentRouteName;
}, function (newState, oldState) {
if (newState) $state.go(newState);
});
// Note that we should probably generate these states
// automatically from data in routeStore.routes, but
// it's done this way for simplicity's sake.
$stateProvider
.state('home', { template: '<home />' })
.state('about', { template: '<about />' })

Conclusion

Resources

--

--

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store