Introduction to Flux and Angular Integration

For my group's thesis project at Hack Reactor, our client is having us design a vendor app for taking and processing drink orders at bars to accompany the app they have already built for end-users. The existing app is our model for the vendor app and employed an interesting design choice: the combined use of Facebook's Flux and Google's AngularJS. While I'm no expert at either technology, I'm going to elaborate on this integration and how our library of choice, flux-angular, handles this unique combination.

What is Flux?

Flux is self-descibed as an "architecture for building client-side web apps," and at its core, its just an architecture pattern for managing data flow throughout your application. Its also commonly referred to as an alternative to the traditional model-view-controller architecture.

Flux is composed of three main parts: the store (which holds your state), actions (which trigger the dispatcher to do something), and a dispatcher (which triggers callbacks registered to it by the store to modify the store). According to Facebook, this allows developers to more easily reason about the data flow throughout their large applications as each component only has one classification of input components and only outputs to/affects another classification of components.

How does it work with Angular?

Shying away from strict adherence to the Flux architecture, flux-angular entirely eschews the use dispatchers altogether, instead building solely on actions and stores.

An example of an $store factory (taken from the README) would look like this for a simple Todo application:

angular.module('app', ['flux'])
.factory('$store', function (flux, $actions) {
    return flux.store({
        todos: [],
        actions: [
            $actions.addTodo
        ],
        addTodo: function (title) {
            this.todos.push({title: title, created: Date.now()});
            this.emitChange();
        },
        exports: {
            getTodos: function () {
                return this.todos;
            }
        }
    });
});

This $store has an array to Todo items which will be the source of truth for these items in the application.

addTodo is an action that can modify the $store whenever called. It also calls emitChange(), emitting a change event whenever the $store is changed; this will become useful when we have controllers in our application that want to bind their $scope to a part of the $store.

We also export a getTodos getter function so that when a controller wants to update its $scope with the latest $store data, it can bind to that data without worrying about later modifying the $store itself.

In order to use the addTodo function in a controller (e.g. $actions.addTodo('go to the store')), we must first bind the $store's actions to the $actions factory:

angular.module('app', ['flux'])
.factory('$actions', function (flux) {
    return flux.actions([
        'addTodo',
    ]);
});

Now, elsewhere in some other controller, we can do this:

.controller('MyCtrl', function ($scope, $store, $actions) {

    $store.bindTo($scope, function () {
        $scope.todos = $store.getTodos();
    });

    $scope.title = '';
    $scope.addTodo = function () {
        $actions.addTodo($scope.title);
    };
});

The first block lets us update our controller's local $scope anytime the $store changes, presumably preventing us from having to do a massive degree of dirty checking anytime we change something on the $scope.

The second block ties a local $scope.addTodo function to the $store-modifying addTodo function so that our data only has to update in one location from which all other $scopes will derive that data.

I hope this has given you an insight into how the seemingly disparate technologies can be used synergistically. Thanks for reading!