$ngRedux

Bob & Ash

Angular State Problems

  • What is the state?
  • Where is the state?
  • How to update the state?

Looking forward

  • Angular 2
  • Less dependant on Angular 1
  • Smart / dumb components

Redux + Angular

Demo simple phones app

angular.module('starter')
    .config(appConfig);


appConfig.$inject = ['$ngReduxProvider', 'rootReducerProvider'];


function appConfig($ngReduxProvider, rootReducerProvider) {
    $ngReduxProvider.createStoreWith(rootReducerProvider.$get(), [
        'promiseMiddleware', 
        'loggerMiddleware'
    ]);
}

Configuration

angular.module('starter')
        .factory('rootReducer', rootReducer);


rootReducer.$inject = ['phonesReducer'];


function rootReducer(phonesReducer) {
    return Redux.combineReducers({
        phones: phonesReducer
    });
}

Root Reducer

...
function reducer(state, action) {
    var initialState = {
        phones: []
    };

    if (angular.isUndefined(state)) {
        return angular.copy(initialState);
    }

    switch (action.type) {
        case 'CREATE_PHONE':
            state.phones.push(action.payload);

            break;
        case 'SET_PHONES_FULFILLED' :
            state = angular.copy(action.payload);

            break;
    }


    return state;
}

Reducer

...
function PhonesController($scope, $ngRedux) {
    var vm = this;

    var unsubscribe = $ngRedux.connect(mapStateToVm)(vm);

    $scope.$on('$destroy', unsubscribe);

    function mapStateToVm(state) {
        return {
            phones: state.phones
        };
    }
}    

Connect state to VM

...
function phonesActions(phonesService) {
    return {
        createPhone: createPhone,
        setPhones: setPhones
    };

    function createPhone(phone) {
        return {
            type: 'CREATE_PHONE',
            payload: phone
        };
    }

    function setPhones() {
        return {
            type: 'SET_PHONES',
            payload: {
                promise: phonesService.getPhones()
            }
        };
    }
}    

Action creators

...
function PhonesController($scope, $ngRedux, phonesActions) {
    var vm = this;
    var unsubscribe = $ngRedux.connect(mapStateToVm, phonesActions)(vm);

    vm.onSubmit = onSubmit;

    $scope.$on('$destroy', unsubscribe);

    vm.setPhones();

    function mapStateToVm(state) {
        return {
            phones: state.phones
        };
    }

    function onSubmit(phone) {
        vm.createPhone(phone);
    }
}

Dispatch actions from VM

<h1 ng-bind="vm.title"></h1>

<form name="phoneCreateForm" ng-submit="vm.onSubmit(vm.newPhone)">

    <input type="text" name="title" autocomplete="off" ng-model="vm.newPhone"/>

    <button type="submit">Create phone</button>
</form>

<ul>
    <li ng-repeat="phone in vm.phones" ng-bind="phone"></li>
</ul>

Template

function thunkMiddleware(store) {
    return function (next) {
        return function (action) {
            if (typeof action === 'function') {
                return action(store.dispatch, store.getState);
            }

            return next(action);
        };
    };
}

Middleware

Benefits

  • Easy unit testing
  • Powerful middleware
  • Discoverable set of actions
  • Asynchronous state representation
  • Improved reliability

Goodies

Let's start hacking

  • Combine reducers
  • Set initial state for stories
  • Connect Main component to vm
  • Fetch stories using redux
  • Create STORY_FINISHED action
  • Pass action through to components
  • Add unit tests
  • Show loading indicator
  • Create time out for notification

Workshop steps

ng-redux session

By Bob Bijvoet

ng-redux session

  • 2,278