angular js meetup

13
Building up with AngularJS design patterns for dealing with UI complexity. Greg Weber yap.TV

Upload: anton-kropp

Post on 05-Jul-2015

379 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Angular js meetup

Building up with AngularJS

design patterns for dealing with UI complexity.

Greg Weber yap.TV

Page 2: Angular js meetup

You chose AngularJS. Good job!

A: Use plain-old JS object, don't need to inherit from a special base: that gives us

greater flexibility.

Q: Why a good framework such as AngularJS?A: 2-way data-binding eases your pain.

Q: Why AngularJS instead of other 2-way data-binding frameworks?

Note: I am not saying that AngularJS is superior to all other frameworks or that it is the best choice for your team and your project.

Page 3: Angular js meetup

Keeping Data up to date* AngularJS keeps the *view* up to date based on the data in the controller.

Problem: modularity demands different controllers communicating via services.

* What happens when a view uses data that is changed in another view?

Page 4: Angular js meetup

Growing complexity

// in servicevar data = []changeData = => $http('api').success (data) => data = []

return { data: data }

// in first controller$scope.data = service.data

// in second controllerservice.changeData()

Complexity Fail: the controller is referencing the original data, doesn't know about new value

// in controller$http('api').success (data) => $scope.data = data

Simplicy & Happiness Complexity & Sadness

Page 5: Angular js meetup

(Overly) simple approach: placing data on the $rootScope and watching it on different controllers.Problems: This could lead to a collision, and also in the case of an isolated scope will not be propagated.

var myModule = angular.module('myModule', []);myModule.factory('mySharedService', function($rootScope) { var sharedService = {}; // expose service data to angular scope $rootScope.sharedData = sharedService.data = {}; sharedService.data.message = '';

return sharedService;});

http://jsfiddle.net/VxafF/

function ControllerZero($scope, sharedService) { $scope.handleClick = function(msg) { sharedService.data.message = msg; }; $scope.$watch('sharedData.message', function(msg) { $scope.message = msg; });}function ControllerOne($scope, sharedService) { $scope.$watch('sharedData.message', function() { $scope.message = 'ONE: ' + sharedService.data.message; });}

Page 6: Angular js meetup

Using events

http://jsfiddle.net/VxafF/

Using events we can clearly communicate between controllers. And when we are communicating with code not integrated with angular, this is often the best approachProblem:

● using fragile strings. Potential (unexplored) solution: use signals.js or use variables that contain the string names

● Usage is a bit more obscure: we will likely end up broadcasting events to every controller whether they care about them or not. We will search for a string to find the event source rather than looking for a service

● Some boilerplate in the controller

myModule.run(function($rootScope) { $rootScope.$on('handleEmit', function(event, args) { $rootScope.$broadcast('handleBroadcast', args); });});

function ControllerZero($scope) { $scope.handleClick = function(msg) { $scope.$emit('handleEmit', {message: msg}); };}

function ControllerOne($scope) { $scope.$on('handleBroadcast', function(event, args) { $scope.message = 'ONE: ' + args.message; }); }

Page 7: Angular js meetup

Communication via services: getters

// in service$rootScope.on 'change', changeData$rootScope.broadcast('event', data)

// in controller$scope.on('event', ...)

// another controller$rootScope.broadcast('change', [])

In AngularJS this can be changed to a function call

// in service var data = [] return { changeData: => ... getData: => return data }

// in controller, assign a function $scope.data = service.getData // in view: ng-bind="data()" // could instead $watch the getter

// another controller service.changeData([])

Events

Page 8: Angular js meetup

Communication via services: mutation// in servicevar data = []var changeData = => $http(...).success (data) => data.length = 0 data.push(d) for d in data

return { data: data changeData: changeData}

// in controller$scope.data = service.data

Page 9: Angular js meetup

Dealing with complexity: not AngularJS specific

* complex data modeling with adt.js* managing complex UI State with statecharts

Page 10: Angular js meetup

Data modeling with adt.js

Facebook feed =>

Each Facebook feed item can be an entirely different kind of data:

● picture● video● link share● status update● surveys

Original code: mostly undefined/null object fields (single table inheritance), type is differentiated by a 'kind' field.

https://github.com/natefaubion/adt.js

New code: a DRY schema that does some data conversion/validation, and it is clear what fields are actually supposed to exist. Our code is our documentation.

A schema is just a key-pair of field name and a function that can coerce the data (parseInt) or throw an exception.

Page 11: Angular js meetup

Statecharts: dealing with complexity

Solution: be very *explicit* about using state.Statecharts were created to manage the complexity of Jet Fighter software. The existing giant specification still did not explain how everything interacted. Using statecharts they were able to document the interaction and communicate it to non-engineers.

Problem: Our UI has implicit state mutation:we switch from one view (state) to another. What transitions are valid? What should happen as state changes? How do we handle concurrent states (different views at once, popups, etc)?

Page 12: Angular js meetup

Statechart: alternatives* Just use routing. Problems: concurrent states, doing proper nested state transitions, remembering history of different branches.* Just use a FSM (multiple FSMs for concurrent states). Problem: Nested states* Stativus library: full-featured, large code base, some bugs* A few other non-maintained/GPL libraries* Wrote my own StateChart implemenation instead. It is smaller & levarages TypeScript. Will open source soon.

Page 13: Angular js meetup

Statecharts: code

state.goTo()exit existing states & enter new state, calling all exit and enter callbacksexiting creates a history state that we can go back (like a back button)

exiting: authenticate history of rootentering loggedinlogged in & startingentering displayentering guideentering guide-Tuesdayexiting: guide-Tuesday history of guideexiting: guide history of displayentering showsentering favoritesentering myNewexiting: myNew history of favoritesexiting: favorites history of showsentering show-searchexiting: show-search history of showsexiting: shows history of displayentering guideentering guide-Tuesday