O slideshow foi denunciado.
Utilizamos seu perfil e dados de atividades no LinkedIn para personalizar e exibir anúncios mais relevantes. Altere suas preferências de anúncios quando desejar.

Design strategies for AngularJS

3.225 visualizações

Publicada em

A talk given at Silicon Valley CodeCamp by Somik Raha and Kai Wu.

Publicada em: Educação
  • ★★ How Long Does She Want You to Last? ★★ A recent study proved that the average man lasts just 2-5 minutes in bed (during intercourse). The study also showed that many women need at least 7-10 minutes of intercourse to reach "The Big O" - and, worse still... 30% of women never get there during intercourse. Clearly, most men are NOT fulfilling there women's needs in bed. Now, as I've said many times - how long you can last is no guarantee of being a GREAT LOVER. But, not being able to last 20, 30 minutes or more, is definitely a sign that you're not going to "set your woman's world on fire" between the sheets. Question is: "What can you do to last longer?" Well, one of the best recommendations I can give you today is to read THIS report. In it, you'll discover a detailed guide to an Ancient Taoist Thrusting Technique that can help any man to last much longer in bed. I can vouch 100% for the technique because my husband has been using it for years :) Here's the link to the report ◆◆◆ http://ishbv.com/rockhardx/pdf
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui
  • ▲▲▲ https://tinyurl.com/rockhardxx
       Responder 
    Tem certeza que deseja  Sim  Não
    Insira sua mensagem aqui

Design strategies for AngularJS

  1. 1. Design Strategies with AngularJS 1
  2. 2. Design Strategies with AngularJS 1 Somik Raha
  3. 3. Design Strategies with AngularJS Somik Raha Kai Wu 1
  4. 4. Design Strategies with AngularJS Somik Raha Kai Wu 1 #smartorgdev
  5. 5. Rip Van Winkle Slept through the American Revolution Slept off in 2004 and woke up in 2014 2
  6. 6. 3
  7. 7. 2004… 3
  8. 8. 2004… 3
  9. 9. 2004… C++ 3
  10. 10. 2004… C++ Java 3
  11. 11. 2004… C++ Java Microsoft 3
  12. 12. 2004… C++ Java Microsoft Sun 3
  13. 13. 2004… C++ Java Microsoft Sun #smartorgdev 3
  14. 14. 2014. C++ Java Microsoft Sun #smartorgdev 4
  15. 15. 2014. Javascript #smartorgdev 4
  16. 16. Backend #smartorgdev 5
  17. 17. Backend Middleware #smartorgdev 5
  18. 18. Backend Middleware Front-end #smartorgdev 5
  19. 19. Backend Middleware Front-end #smartorgdev 5
  20. 20. Backend Middleware Front-end #smartorgdev 6
  21. 21. Super-heroic Javascript framework #smartorgdev 7
  22. 22. Super-heroic Javascript framework #smartorgdev 7
  23. 23. First reaction I don’t get it. Backbone is great for us. #smartorgdev 8
  24. 24. Second reaction Whoa!! #smartorgdev 9
  25. 25. Backbone learning curve AngularJS learning curve Flattens quickly Minimal concepts 10 Service Directives Controllers and views Staircase … !
  26. 26. Backbone learning curve AngularJS learning curve Flattens quickly Minimal concepts 10 Ben Nadel’s blog
  27. 27. Stats comparing Backbone with AngularJS AppStructure Wizard #smartorgdev 11
  28. 28. Stats comparing Backbone with AngularJS AppStructure Wizard #smartorgdev 11
  29. 29. Stats comparing Backbone with AngularJS AppStructure Wizard #smartorgdev 11
  30. 30. Three Kinds of Scenarios Single Page Application Multi-Page Application Legacy Application Classic Sophisticated Convoluted #smartorgdev 12
  31. 31. Multi-Page Application Browser loads entire page e.g. Login e.g. Show Projects Page 1 Page 2 Page 3 View 1 View 2 View 3 Controller 1 Controller 2 Controller 3 Route 1 Route 2 Route 3 /login /showProjects /… Map routes to controllers and views #smartorgdev 13
  32. 32. angular.module('myApp', [ 'ngRoute', … ]).config(function ($routeProvider) { $routeProvider.when('/route1', { controller: 'Controller1 as c1', templateUrl: 'views/view1.html', }).when('/route2', { controller: 'Controller2 as c2', templateUrl: 'views/view2.html', }).otherwise({ redirectTo: '/route1' }); }); Route1 Controller1 View1 Route2 Controller2 View2 Map routes to controllers and views app.js 14
  33. 33. angular.module('myApp', [ 'ngRoute', … ]).config(function ($routeProvider) { $routeProvider.when('/showProjects', { controller: 'ShowProjectsController as show', templateUrl: ‘views/showProjects.html’, }).when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }).otherwise({ redirectTo: '/login' }); }); Routes! http://../login http://../showProjects app.js 15
  34. 34. angular.module('myApp', [ 'ngRoute', … ]).config(function ($routeProvider) { $routeProvider.when('/showProjects', { controller: 'ShowProjectsController as show', templateUrl: ‘views/showProjects.html’, }).when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }).otherwise({ redirectTo: '/login' }); }); Routes! http://../login http://../showProjects app.js 15
  35. 35. when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }) Routes! http://../login http://../showProjects app.js 16
  36. 36. ! class LoginController { $location: ng.ILocationService; password: string; userName: string; constructor($location:ng.ILocationService) { this.$location = $location; this.userName = ""; this.password = ""; } doLogin() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode(this.userName, this.password) .then((response) => this.onLoginSuccess(response)) } onLoginSuccess(response){ if (response.status) { this.$location.path("/showProjects"); } else { this.$location.path("/login"); console.log("Login failed. You cannot proceed.") } } } ! ! <form name="loginForm" class="navbar-form navbar-left form-signin"> <input ng-model="login.userName" class="form-control" placeholder="User Name" required autofocus> <input ng-model="login.password" type="password" class="form-control" placeholder="Password" required> <button ng-click="login.doLogin()" class="btn btn-primary" type="submit">Sign in</button> </form> login.html TypeScript Simple OO Code AngularJS Creates an object in app.js app.js when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }) 17
  37. 37. ! class LoginController { $location: ng.ILocationService; password: string; userName: string; constructor($location:ng.ILocationService) { this.$location = $location; this.userName = ""; this.password = ""; } doLogin() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode(this.userName, this.password) .then((response) => this.onLoginSuccess(response)) } onLoginSuccess(response){ if (response.status) { this.$location.path("/showProjects"); } else { this.$location.path("/login"); console.log("Login failed. You cannot proceed.") } } } ! ! <form name="loginForm" class="navbar-form navbar-left form-signin"> <input ng-model="login.userName" class="form-control" placeholder="User Name" required autofocus> <input ng-model="login.password" type="password" class="form-control" placeholder="Password" required> <button ng-click="login.doLogin()" class="btn btn-primary" type="submit">Sign in</button> </form> login.html TypeScript Simple OO Code AngularJS Creates an object in app.js app.js Pattern ! Controller in Typescript Classes! ! Packages the controller logic and makes it much easier to read and test. when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }) 17
  38. 38. ! class LoginController { $location: ng.ILocationService; password: string; userName: string; constructor($location:ng.ILocationService) { this.$location = $location; this.userName = ""; this.password = ""; } doLogin() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode(this.userName, this.password) .then((response) => this.onLoginSuccess(response)) } onLoginSuccess(response){ if (response.status) { this.$location.path("/showProjects"); } else { this.$location.path("/login"); console.log("Login failed. You cannot proceed.") } } } ! ! <form name="loginForm" class="navbar-form navbar-left form-signin"> <input ng-model="login.userName" class="form-control" placeholder="User Name" required autofocus> <input ng-model="login.password" type="password" class="form-control" placeholder="Password" required> <button ng-click="login.doLogin()" class="btn btn-primary" type="submit">Sign in</button> </form> login.html TypeScript Simple OO Code AngularJS Creates an object in app.js app.js when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }) 17
  39. 39. ! class LoginController { $location: ng.ILocationService; password: string; userName: string; constructor($location:ng.ILocationService) { this.$location = $location; this.userName = ""; this.password = ""; } doLogin() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode(this.userName, this.password) .then((response) => this.onLoginSuccess(response)) } onLoginSuccess(response){ if (response.status) { this.$location.path("/showProjects"); } else { this.$location.path("/login"); console.log("Login failed. You cannot proceed.") } } } ! ! <form name="loginForm" class="navbar-form navbar-left form-signin"> <input ng-model="login.userName" class="form-control" placeholder="User Name" required autofocus> <input ng-model="login.password" type="password" class="form-control" placeholder="Password" required> <button ng-click="login.doLogin()" class="btn btn-primary" type="submit">Sign in</button> </form> login.html TypeScript Simple OO Code AngularJS Creates an object in app.js app.js when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }) 17
  40. 40. ! class LoginController { $location: ng.ILocationService; password: string; userName: string; constructor($location:ng.ILocationService) { this.$location = $location; this.userName = ""; this.password = ""; } doLogin() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode(this.userName, this.password) .then((response) => this.onLoginSuccess(response)) } onLoginSuccess(response){ if (response.status) { this.$location.path("/showProjects"); } else { this.$location.path("/login"); console.log("Login failed. You cannot proceed.") } } } ! ! <form name="loginForm" class="navbar-form navbar-left form-signin"> <input ng-model="login.userName" class="form-control" placeholder="User Name" required autofocus> <input ng-model="login.password" type="password" class="form-control" placeholder="Password" required> <button ng-click="login.doLogin()" class="btn btn-primary" type="submit">Sign in</button> </form> login.html TypeScript Simple OO Code AngularJS Creates an object in app.js app.js when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }) 17
  41. 41. ! class LoginController { $location: ng.ILocationService; password: string; userName: string; constructor($location:ng.ILocationService) { this.$location = $location; this.userName = ""; this.password = ""; } doLogin() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode(this.userName, this.password) .then((response) => this.onLoginSuccess(response)) } onLoginSuccess(response){ if (response.status) { this.$location.path("/showProjects"); } else { this.$location.path("/login"); console.log("Login failed. You cannot proceed.") } } } ! ! <form name="loginForm" class="navbar-form navbar-left form-signin"> <input ng-model="login.userName" class="form-control" placeholder="User Name" required autofocus> <input ng-model="login.password" type="password" class="form-control" placeholder="Password" required> <button ng-click="login.doLogin()" class="btn btn-primary" type="submit">Sign in</button> </form> login.html TypeScript Simple OO Code AngularJS Creates an object in app.js app.js when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }) 17
  42. 42. ! class LoginController { $location: ng.ILocationService; password: string; userName: string; constructor($location:ng.ILocationService) { this.$location = $location; this.userName = ""; this.password = ""; } doLogin() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode(this.userName, this.password) .then((response) => this.onLoginSuccess(response)) } onLoginSuccess(response){ if (response.status) { this.$location.path("/showProjects"); } else { this.$location.path("/login"); console.log("Login failed. You cannot proceed.") } } } ! ! <form name="loginForm" class="navbar-form navbar-left form-signin"> <input ng-model="login.userName" class="form-control" placeholder="User Name" required autofocus> <input ng-model="login.password" type="password" class="form-control" placeholder="Password" required> <button ng-click="login.doLogin()" class="btn btn-primary" type="submit">Sign in</button> </form> login.html TypeScript Simple OO Code AngularJS Creates an object in app.js app.js Optional Pattern ! Named Controller Objects! ! Maintains modularity and avoids having to put data into scope objects, which hold so much other stuff, making it easier to debug. when('/login', { controller: 'LoginController as login', templateUrl: 'views/login.html', }) 17
  43. 43. ! class LoginController { $location: ng.ILocationService; password: string; userName: string; constructor($location:ng.ILocationService) { this.$location = $location; this.userName = ""; this.password = ""; } doLogin() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode(this.userName, this.password) .then((response) => this.onLoginSuccess(response)) } onLoginSuccess(response){ if (response.status) { this.$location.path("/showProjects"); } else { this.$location.path("/login"); console.log("Login failed. You cannot proceed.") } } } ! ! function LoginController($scope, $location) { $scope.userName = ""; $scope.password = ""; $scope.doLogin = function() { // Call your login code with a call back to loginSuccessFn callSomeAuthCode($scope.userName, $scope.password) .then($scope.onLoginSuccess(response)) } $scope.onLoginSuccess = function(response){ if (response.status) { $location.path("/showProjects"); } else { $location.path("/login"); console.log("Login failed. You cannot proceed.") } } } !! Typescript provides more readable structure More funky All initialization is in constructor Code completion; No $scope Initialization is not clearly demarcated, declarations interspersed with execution ! No code completion 18 Controller in Typescript Classes
  44. 44. 19
  45. 45. 19
  46. 46. Single-Page Application Rich interactions within a single page, loaded only once Navigation Workspace Actions Menu #smartorgdev 20
  47. 47. #smartorgdev 21
  48. 48. #smartorgdev 21
  49. 49. If we have only one controller and one view, how do we prevent our code from getting bloated? 22
  50. 50. Directives to the rescue index.html <body ng-app="myApp" ng-controller="myController"> <div class="row"> <div top-menu-view …></div> </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> </div> </div> </div> … </body> 23 template.html directive.js
  51. 51. Directives to the rescue index.html <body ng-app="myApp" ng-controller="myController"> <div class="row"> <div top-menu-view …></div> </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> </div> </div> </div> … </body> 23 template.html directive.js Pattern: ! Decompose view with directives
  52. 52. Directives to the rescue index.html <body ng-app="myApp" ng-controller="myController"> <div class="row"> <div top-menu-view …></div> </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> </div> </div> </div> … </body> 23 template.html directive.js
  53. 53. But wait, how do we pass data between directives? Navigation Workspace Actions Menu e.g. How does the Navigation directive find out about a selection in the Menu directive? #smartorgdev 24
  54. 54. But wait, how do we pass data between directives? Navigation Workspace Actions Menu e.g. list of trees e.g. How does the Navigation directive find out which tree has been selected in the Menu directive? #smartorgdev 25
  55. 55. myController angular.module('myApp') .controller('myController', function ($scope, $route, $routeParams, $location) { $scope.action = 'login'; $scope.$on("$routeChangeSuccess", function( $currentRoute, $previousRoute ) { $scope.action = $route.current.action; }); $scope.login = function() { // do login, and on success: $location.path('/home'); } $scope.onSelectTree = function(treeID) { // go fetch the tree using the treeID, … // myTree holds the tree $scope.$broadcast("treeLoaded", { "myTree": myTree }); } }); navigation directive angular.module('myApp') .directive("navigation", function() { return { restrict: 'A', scope: { myTree: '=' } }, templateUrl: '...', link: function(scope) { scope.$on('treeLoaded', function() { makeTreeWith(scope.myTree); //.. } } }); menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 26
  56. 56. myController angular.module('myApp') .controller('myController', function ($scope, $route, $routeParams, $location) { $scope.action = 'login'; $scope.$on("$routeChangeSuccess", function( $currentRoute, $previousRoute ) { $scope.action = $route.current.action; }); $scope.login = function() { // do login, and on success: $location.path('/home'); } $scope.onSelectTree = function(treeID) { // go fetch the tree using the treeID, … // myTree holds the tree $scope.$broadcast("treeLoaded", { "myTree": myTree }); } }); navigation directive angular.module('myApp') .directive("navigation", function() { return { restrict: 'A', scope: { myTree: '=' } }, templateUrl: '...', link: function(scope) { scope.$on('treeLoaded', function() { makeTreeWith(scope.myTree); //.. } } }); menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 26
  57. 57. myController angular.module('myApp') .controller('myController', function ($scope, $route, $routeParams, $location) { $scope.action = 'login'; $scope.$on("$routeChangeSuccess", function( $currentRoute, $previousRoute ) { $scope.action = $route.current.action; }); $scope.login = function() { // do login, and on success: $location.path('/home'); } $scope.onSelectTree = function(treeID) { // go fetch the tree using the treeID, … // myTree holds the tree $scope.$broadcast("treeLoaded", { "myTree": myTree }); } }); navigation directive angular.module('myApp') .directive("navigation", function() { return { restrict: 'A', scope: { myTree: '=' } }, templateUrl: '...', link: function(scope) { scope.$on('treeLoaded', function() { makeTreeWith(scope.myTree); //.. } } }); menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 26
  58. 58. myController angular.module('myApp') .controller('myController', function ($scope, $route, $routeParams, $location) { $scope.action = 'login'; $scope.$on("$routeChangeSuccess", function( $currentRoute, $previousRoute ) { $scope.action = $route.current.action; }); $scope.login = function() { // do login, and on success: $location.path('/home'); } $scope.onSelectTree = function(treeID) { // go fetch the tree using the treeID, … // myTree holds the tree $scope.$broadcast("treeLoaded", { "myTree": myTree }); } }); navigation directive angular.module('myApp') .directive("navigation", function() { return { restrict: 'A', scope: { myTree: '=' } }, templateUrl: '...', link: function(scope) { scope.$on('treeLoaded', function() { makeTreeWith(scope.myTree); //.. } } }); menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 26
  59. 59. myController angular.module('myApp') .controller('myController', function ($scope, $route, $routeParams, $location) { $scope.action = 'login'; $scope.$on("$routeChangeSuccess", function( $currentRoute, $previousRoute ) { $scope.action = $route.current.action; }); $scope.login = function() { // do login, and on success: $location.path('/home'); } $scope.onSelectTree = function(treeID) { // go fetch the tree using the treeID, … // myTree holds the tree $scope.$broadcast("treeLoaded", { "myTree": myTree }); } }); navigation directive angular.module('myApp') .directive("navigation", function() { return { restrict: 'A', scope: { myTree: '=' } }, templateUrl: '...', link: function(scope) { scope.$on('treeLoaded', function() { makeTreeWith(scope.myTree); //.. } } }); menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 26
  60. 60. myController angular.module('myApp') .controller('myController', function ($scope, $route, $routeParams, $location) { $scope.action = 'login'; $scope.$on("$routeChangeSuccess", function( $currentRoute, $previousRoute ) { $scope.action = $route.current.action; }); $scope.login = function() { // do login, and on success: $location.path('/home'); } $scope.onSelectTree = function(treeID) { // go fetch the tree using the treeID, … // myTree holds the tree $scope.$broadcast("treeLoaded", { "myTree": myTree }); } }); navigation directive angular.module('myApp') .directive("navigation", function() { return { restrict: 'A', scope: { myTree: '=' } }, templateUrl: '...', link: function(scope) { scope.$on('treeLoaded', function() { makeTreeWith(scope.myTree); //.. } } }); menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 26
  61. 61. myController angular.module('myApp') .controller('myController', function ($scope, $route, $routeParams, $location) { $scope.action = 'login'; $scope.$on("$routeChangeSuccess", function( $currentRoute, $previousRoute ) { $scope.action = $route.current.action; }); $scope.login = function() { // do login, and on success: $location.path('/home'); } $scope.onSelectTree = function(treeID) { // go fetch the tree using the treeID, … // myTree holds the tree $scope.$broadcast("treeLoaded", { "myTree": myTree }); } }); navigation directive angular.module('myApp') .directive("navigation", function() { return { restrict: 'A', scope: { myTree: '=' } }, templateUrl: '...', link: function(scope) { scope.$on('treeLoaded', function() { makeTreeWith(scope.myTree); //.. } } }); menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); But wait, how does scope.onSelectTree work correctly when called in the menu directive? 26
  62. 62. index.html menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 27 <body ng-app="myApp" ng-controller="myController"> <div id="homescope"> <div class="row"> <div top-menu-view …></div> </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> </div> </div> </div> … </body>
  63. 63. index.html menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 27 <body ng-app="myApp" ng-controller="myController"> <div id="homescope"> <div class="row"> <div top-menu-view …></div> </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> </div> </div> </div> … </body>
  64. 64. index.html menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 27 <body ng-app="myApp" ng-controller="myController"> <div id="homescope"> <div class="row"> <div top-menu-view …></div> </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> </div> </div> </div> … </body>
  65. 65. <div top-menu-view menu-data="menuData" on-select-tree="onSelectTree(treeID)"></div> menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 28 index.html <body ng-app="myApp" ng-controller="myController"> <div id="homescope"> <div class="row"> </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> </div> </div> </div> … </body>
  66. 66. <div top-menu-view menu-data="menuData" on-select-tree="onSelectTree(treeID)"></div> menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 28 index.html <body ng-app="myApp" ng-controller="myController"> <div id="homescope"> <div class="row"> </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> </div> </div> </div> … </body>
  67. 67. index.html <body ng-app="myApp" ng-controller="myController"> <div id="homescope"> <div class="row"> <div top-menu-view menu-data="menuData" on-select-tree="onSelectTree(treeID)"></div> menu directive angular.module('myApp') .directive("topMenuView", function() { return { restrict: 'A', scope: { menuData: '=', onSelectTree: '&' } }, templateUrl: '...', link: function(scope) { scope.chooseTree = function(tree){ scope.onSelectTree({treeID: tree.id}); }; } }); 28 </div> <div class="row"> <div id="leftPanel"> <div nav-widget …></div> </div> <div id="middlePanel"> <div workspace-contents …></div> </div> <div id="rightPanel" > <div action-menu …></div> Pattern: ! Pass Controller Functions as Directive Attributes </div> </div> </div> … </body>
  68. 68. Legacy Application Non-JS MVC model and cannot make direct web calls from JS to your application Generate HTML stubs that invoke “widgets” using directives ! #smartorgdev 29
  69. 69. 30
  70. 70. 30
  71. 71. In your legacy web application, render this html: <div id="mywidgetOuterDiv">! <div id="mywidget" class="" ng-controller="MyWidgetCtrl">! <div mywidget-directive! input-data="inputData" ! setup-data="setupData()">! </div> ! </div>! </div>! ! and this JS: jsCode = "APP.myWidgetConfig = { inputData: {…} }"! In your JS code, bootstrap your widget: angular.bootstrap($('#mywidgetOuterDiv'), ['myApp']);! var scope = $('#mywidget').scope();! scope.setupData(APP.myWidgetConfig);! ! 31
  72. 72. In your legacy web application, render this html: <div id="mywidgetOuterDiv">! <div id="mywidget" class="" ng-controller="MyWidgetCtrl">! <div mywidget-directive! input-data="inputData" ! setup-data="setupData()">! </div> ! </div>! </div>! ! widget directive and this JS: jsCode = "APP.myWidgetConfig = { inputData: {…} }"! In your JS code, bootstrap your widget: angular.bootstrap($('#mywidgetOuterDiv'), ['myApp']);! var scope = $('#mywidget').scope();! scope.setupData(APP.myWidgetConfig);! ! 31
  73. 73. In your legacy web application, render this html: <div id="mywidgetOuterDiv">! <div id="mywidget" class="" ng-controller="MyWidgetCtrl">! <div mywidget-directive! input-data="inputData" ! setup-data="setupData()">! </div> ! </div>! </div>! ! widget directive In your JS code, bootstrap your widget: angular.bootstrap($('#mywidgetOuterDiv'), ['myApp']);! var scope = $('#mywidget').scope();! scope.setupData(APP.myWidgetConfig);! ! widget controller and this JS: jsCode = "APP.myWidgetConfig = { inputData: {…} }"! 31
  74. 74. In your legacy web application, render this html: <div id="mywidgetOuterDiv">! <div id="mywidget" class="" ng-controller="MyWidgetCtrl">! <div mywidget-directive! input-data="inputData" ! setup-data="setupData()">! </div> ! </div>! </div>! ! widget directive In your JS code, bootstrap your widget: angular.bootstrap($('#mywidgetOuterDiv'), ['myApp']);! var scope = $('#mywidget').scope();! scope.setupData(APP.myWidgetConfig);! ! widget controller widget container and this JS: jsCode = "APP.myWidgetConfig = { inputData: {…} }"! 31
  75. 75. In your legacy web application, render this html: <div id="mywidgetOuterDiv">! <div id="mywidget" class="" ng-controller="MyWidgetCtrl">! <div mywidget-directive! input-data="inputData" ! setup-data="setupData()">! </div> ! </div>! </div>! ! widget directive In your JS code, bootstrap your widget: angular.bootstrap($('#mywidgetOuterDiv'), ['myApp']);! var scope = $('#mywidget').scope();! scope.setupData(APP.myWidgetConfig);! ! widget controller widget container and this JS: jsCode = "APP.myWidgetConfig = { inputData: {…} }"! 31
  76. 76. In your legacy web application, render this html: <div id="mywidgetOuterDiv">! <div id="mywidget" class="" ng-controller="MyWidgetCtrl">! <div mywidget-directive! input-data="inputData" ! setup-data="setupData()">! </div> ! </div>! </div>! ! widget directive In your JS code, bootstrap your widget: angular.bootstrap($('#mywidgetOuterDiv'), ['myApp']);! var scope = $('#mywidget').scope();! scope.setupData(APP.myWidgetConfig);! ! widget controller widget container and this JS: jsCode = "APP.myWidgetConfig = { inputData: {…} }"! 31
  77. 77. In your legacy web application, render this html: <div id="mywidgetOuterDiv">! <div id="mywidget" class="" ng-controller="MyWidgetCtrl">! <div mywidget-directive! input-data="inputData" ! setup-data="setupData()">! </div> ! </div>! </div>! ! widget directive In your JS code, bootstrap your widget: angular.bootstrap($('#mywidgetOuterDiv'), ['myApp']);! var scope = $('#mywidget').scope();! scope.setupData(APP.myWidgetConfig);! ! widget controller widget container and this JS: jsCode = "APP.myWidgetConfig = { inputData: {…} }"! 31
  78. 78. In your legacy web application, render this html: <div id="mywidgetOuterDiv">! <div id="mywidget" class="" ng-controller="MyWidgetCtrl">! <div mywidget-directive! input-data="inputData" ! setup-data="setupData()">! </div> ! </div>! </div>! ! widget directive In your JS code, bootstrap your widget: angular.bootstrap($('#mywidgetOuterDiv'), ['myApp']);! var scope = $('#mywidget').scope();! scope.setupData(APP.myWidgetConfig);! ! widget controller widget container and this JS: jsCode = "APP.myWidgetConfig = { inputData: {…} }"! Pattern: ! Dynamically invoke angular application 31
  79. 79. angular.module('myApp')! .controller('MyWidgetCtrl', function($scope) {! $scope.setupData = function(myWidgetConfig:MyWidgetConfig) {! if (!$scope.inputData && !myWidgetConfig) {! addTablesConfig = window.standalone.myWidgetConfig;! } else if ($scope.inputData && !myWidgetConfig) {! return;! }! $scope.inputData = myWidgetConfig.inputData;! };! })! .directive('mywidgetDirective', function() {! var templateUrl = '/path/to/template.html';! if (!window.production) {! templateUrl = 'localpath/to/template.html'! }! return {! restrict: 'A',! templateUrl: templateUrl,! scope: {! inputData: '=',! setupData: '&'! },! link: function (scope, elem, attrs, ctrl) {! }! }! });! ! Data made available to directive scope standalone.js 32
  80. 80. angular.module('myApp')! .controller('MyWidgetCtrl', function($scope) {! $scope.setupData = function(myWidgetConfig:MyWidgetConfig) {! if (!$scope.inputData && !myWidgetConfig) {! addTablesConfig = window.standalone.myWidgetConfig;! } else if ($scope.inputData && !myWidgetConfig) {! return;! }! $scope.inputData = myWidgetConfig.inputData;! };! })! .directive('mywidgetDirective', function() {! var templateUrl = '/path/to/template.html';! if (!window.production) {! templateUrl = 'localpath/to/template.html'! }! return {! restrict: 'A',! templateUrl: templateUrl,! scope: {! inputData: '=',! setupData: '&'! },! link: function (scope, elem, attrs, ctrl) {! }! }! });! ! Data made available to directive scope standalone.js 32
  81. 81. angular.module('myApp')! .controller('MyWidgetCtrl', function($scope) {! $scope.setupData = function(myWidgetConfig:MyWidgetConfig) {! if (!$scope.inputData && !myWidgetConfig) {! addTablesConfig = window.standalone.myWidgetConfig;! } else if ($scope.inputData && !myWidgetConfig) {! return;! }! $scope.inputData = myWidgetConfig.inputData;! };! })! .directive('mywidgetDirective', function() {! var templateUrl = '/path/to/template.html';! if (!window.production) {! templateUrl = 'localpath/to/template.html'! }! return {! restrict: 'A',! templateUrl: templateUrl,! scope: {! inputData: '=',! setupData: '&'! },! link: function (scope, elem, attrs, ctrl) {! }! }! });! ! Data made available to directive scope standalone.js 32
  82. 82. angular.module('myApp')! .controller('MyWidgetCtrl', function($scope) {! $scope.setupData = function(myWidgetConfig:MyWidgetConfig) {! if (!$scope.inputData && !myWidgetConfig) {! addTablesConfig = window.standalone.myWidgetConfig;! } else if ($scope.inputData && !myWidgetConfig) {! return;! }! $scope.inputData = myWidgetConfig.inputData;! };! })! .directive('mywidgetDirective', function() {! var templateUrl = '/path/to/template.html';! if (!window.production) {! Allows for standalone templateUrl = 'localpath/to/template.html'! }! return {! restrict: 'A',! templateUrl: templateUrl,! scope: {! inputData: '=',! setupData: '&'! },! link: function (scope, elem, attrs, ctrl) {! }! }! });! ! Data made available to directive scope standalone.js 32 widget testing window.standalone = {! myWidgetConfig: {! inputData: …! }! }! ! standalone index.html
  83. 83. angular.module('myApp')! .controller('MyWidgetCtrl', function($scope) {! $scope.setupData = function(myWidgetConfig:MyWidgetConfig) {! if (!$scope.inputData && !myWidgetConfig) {! addTablesConfig = window.standalone.myWidgetConfig;! } else if ($scope.inputData && !myWidgetConfig) {! return;! }! $scope.inputData = myWidgetConfig.inputData;! };! })! .directive('mywidgetDirective', function() {! var templateUrl = '/path/to/template.html';! if (!window.production) {! Allows for standalone templateUrl = 'localpath/to/template.html'! }! return {! restrict: 'A',! templateUrl: templateUrl,! scope: {! inputData: '=',! setupData: '&'! },! link: function (scope, elem, attrs, ctrl) {! }! }! });! ! Data made available to directive scope standalone.js Pattern: ! Standalone Widget Mode 32 widget testing window.standalone = {! myWidgetConfig: {! inputData: …! }! }! ! standalone index.html
  84. 84. Testing notes Avoid putting business logic in controllers ! Put them in Typescript classes that can be independently tested ! Use HttpMocks to ensure controllers work fine #smartorgdev 33
  85. 85. Old ideas like modularity, once-and-only-once, etc. still apply ! They just look different #smartorgdev 34
  86. 86. Get expert help 35
  87. 87. Join us tomorrow for a Test-Driven Development session ! 10:45 AM Check us out at http://rangal.com and http://smartorg.com #smartorgdev 36
  88. 88. Open House! ! Pattern Summary! ! Controller in Typescript classes (17) Named Controller objects (17) ! Decompose View with Directives (22) ! Pass Controller Functions as Directive Attributes (28) ! Dynamically Invoke Angular Application (31) ! Standalone Widget Mode (32) ! 37 ! Questions for reflection ! What’s your AngularJS adoption experience? ! What have you learned? Write to us! Somik Raha: sraha@smartorg.com Kai Wu: kwu@smartorg.com #smartorgdev

×