Transcript
Page 1: Design strategies for AngularJS

Design Strategies with AngularJS

1

Design Strategies with AngularJS

1

Somik Raha

Design Strategies with AngularJS

1

Somik Raha Kai Wu

Design Strategies with AngularJS

1

smartorgdevSomik Raha Kai Wu

Rip Van Winkle

Slept through the American

Revolution

Slept off in 2004 and woke up in

2014 2

3

2004hellip

3

2004hellip

3

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 2: Design strategies for AngularJS

Design Strategies with AngularJS

1

Somik Raha

Design Strategies with AngularJS

1

Somik Raha Kai Wu

Design Strategies with AngularJS

1

smartorgdevSomik Raha Kai Wu

Rip Van Winkle

Slept through the American

Revolution

Slept off in 2004 and woke up in

2014 2

3

2004hellip

3

2004hellip

3

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 3: Design strategies for AngularJS

Design Strategies with AngularJS

1

Somik Raha Kai Wu

Design Strategies with AngularJS

1

smartorgdevSomik Raha Kai Wu

Rip Van Winkle

Slept through the American

Revolution

Slept off in 2004 and woke up in

2014 2

3

2004hellip

3

2004hellip

3

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 4: Design strategies for AngularJS

Design Strategies with AngularJS

1

smartorgdevSomik Raha Kai Wu

Rip Van Winkle

Slept through the American

Revolution

Slept off in 2004 and woke up in

2014 2

3

2004hellip

3

2004hellip

3

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 5: Design strategies for AngularJS

Rip Van Winkle

Slept through the American

Revolution

Slept off in 2004 and woke up in

2014 2

3

2004hellip

3

2004hellip

3

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 6: Design strategies for AngularJS

3

2004hellip

3

2004hellip

3

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 7: Design strategies for AngularJS

2004hellip

3

2004hellip

3

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 8: Design strategies for AngularJS

2004hellip

3

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 9: Design strategies for AngularJS

2004hellip

C++

3

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 10: Design strategies for AngularJS

2004hellip

C++ Java

3

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 11: Design strategies for AngularJS

2004hellip

C++ JavaMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 12: Design strategies for AngularJS

2004hellip

C++ JavaSunMicrosoft

3

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 13: Design strategies for AngularJS

2004hellip

C++ JavaSunMicrosoft

3smartorgdev

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 14: Design strategies for AngularJS

2014

C++ JavaSunMicrosoft

4smartorgdev

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 15: Design strategies for AngularJS

2014

Javascript4smartorgdev

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 16: Design strategies for AngularJS

Backend

5smartorgdev

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 17: Design strategies for AngularJS

Backend Middleware

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 18: Design strategies for AngularJS

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 19: Design strategies for AngularJS

Backend Middleware Front-end

5smartorgdev

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 20: Design strategies for AngularJS

Backend Middleware Front-end

6smartorgdev

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 21: Design strategies for AngularJS

Super-heroic Javascript framework

7smartorgdev

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 22: Design strategies for AngularJS

Super-heroic Javascript framework

7smartorgdev

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 23: Design strategies for AngularJS

First reaction

I donrsquot get it Backbone is great for us

8smartorgdev

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 24: Design strategies for AngularJS

Second reaction

Whoa

9smartorgdev

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 25: Design strategies for AngularJS

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10

Staircase

Controllers and views

Directives

Servicehellip

10

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 26: Design strategies for AngularJS

Backbone learning curve AngularJS learning curve

Flattens quicklyMinimal concepts

10Ben Nadelrsquos blog

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 27: Design strategies for AngularJS

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 28: Design strategies for AngularJS

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 29: Design strategies for AngularJS

Stats comparing Backbone with AngularJS

AppStructure Wizard

11smartorgdev

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 30: Design strategies for AngularJS

Three Kinds of Scenarios

Single Page Application

Multi-Page Application

Legacy Application

Classic Sophisticated Convoluted

12smartorgdev

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 31: Design strategies for AngularJS

Multi-Page Application

Map routes to controllers and views

Page 1 Page 2 Page 3

eg Logineg Show Projects

View 1 View 2 View 3

Controller 1 Controller 2 Controller 3

Route 1 Route 2 Route 3login showProjects hellip

Browser loads entire page

13smartorgdev

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 32: Design strategies for AngularJS

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(route1 13 controller Controller1 as c113 templateUrl viewsview1html13 )when(route2 13 controller Controller2 as c213 templateUrl viewsview2html13 )otherwise(13 redirectTo route113 )13)13

Route1

View1

Controller1

Route2

View2

Controller2

Map routes to controllers and viewsappjs

14

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 33: Design strategies for AngularJS

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 34: Design strategies for AngularJS

angularmodule(myApp [13 ngRoute13 hellip13])config(function ($routeProvider) 13 $routeProviderwhen(showProjects 13 controller ShowProjectsController as show13 templateUrl lsquoviewsshowProjectshtmlrsquo13 )when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )otherwise(13 redirectTo login13 )13)13

Routeshttplogin

httpshowProjectsappjs

15

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 35: Design strategies for AngularJS

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

Routeshttplogin

httpshowProjectsappjs

16

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 36: Design strategies for AngularJS

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 37: Design strategies for AngularJS

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

Pattern

Controller in Typescript Classes

Packages the controller logic and makes it much easier to read and test

when(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 38: Design strategies for AngularJS

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 39: Design strategies for AngularJS

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 40: Design strategies for AngularJS

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 41: Design strategies for AngularJS

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjswhen(login 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 42: Design strategies for AngularJS

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

ltform name=loginForm class=navbar-form navbar-left form-signingt13 ltinput ng-model=loginuserName class=form-control placeholder=User Name required autofocusgt13 ltinput ng-model=loginpassword type=password class=form-control placeholder=Password requiredgt13 ltbutton ng-click=logindoLogin() class=btn btn-primary type=submitgtSign inltbuttongt13ltformgt

loginhtml

TypeScript Simple OO Code

AngularJS Creates an object in appjs

appjs

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 13 controller LoginController as login13 templateUrl viewsloginhtml13 )13

17

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 43: Design strategies for AngularJS

class LoginController 13 $location ngILocationService13 password string13 userName string13 constructor($locationngILocationService) 13 this$location = $location13 thisuserName = 13 thispassword = 13 13 doLogin() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode(thisuserName thispassword)13 then((response) =gt thisonLoginSuccess(response))13 13 onLoginSuccess(response)13 if (responsestatus) 13 this$locationpath(showProjects)13 else 13 this$locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

function LoginController($scope $location) 13 $scopeuserName = 13 $scopepassword = 13 $scopedoLogin = function() 13 Call your login code with a call back to loginSuccessFn13 callSomeAuthCode($scopeuserName $scopepassword)13 then($scopeonLoginSuccess(response))13 13 $scopeonLoginSuccess = function(response)13 if (responsestatus) 13 $locationpath(showProjects)13 else 13 $locationpath(login)13 consolelog(Login failed You cannot proceed)13 13 1313

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

1818

Controller in Typescript Classes

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 44: Design strategies for AngularJS

19

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 45: Design strategies for AngularJS

19

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 46: Design strategies for AngularJS

Single-Page ApplicationRich interactions within a single page loaded only once

Nav

igat

ion

Workspace

Actio

ns

Menu

20smartorgdev

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 47: Design strategies for AngularJS

21smartorgdev

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 48: Design strategies for AngularJS

21smartorgdev

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 49: Design strategies for AngularJS

If we have only one controller and one view how do we prevent our code from getting

bloated

22

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 50: Design strategies for AngularJS

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 51: Design strategies for AngularJS

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

Pattern Decompose view with directives

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 52: Design strategies for AngularJS

Directives to the rescue

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv class=rowgt13 ltdiv top-menu-view hellipgtltdivgt13 ltdivgt13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt13 13 hellip 13ltbodygt

23

templatehtmldirectivejs

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 53: Design strategies for AngularJS

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out about a selection in the Menu directive

24smartorgdev

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 54: Design strategies for AngularJS

But wait how do we pass data between directives

Nav

igat

ion

Workspace

Actio

ns

Menu

eg How does the Navigation directive find out which tree has been selected in the Menu directive

eg list of trees

25smartorgdev

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 55: Design strategies for AngularJS

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 56: Design strategies for AngularJS

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 57: Design strategies for AngularJS

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 58: Design strategies for AngularJS

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 59: Design strategies for AngularJS

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 60: Design strategies for AngularJS

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

26

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 61: Design strategies for AngularJS

angularmodule(myApp)13 controller(myController 13 function ($scope $route $routeParams $location) 13 $scopeaction = login13 $scope$on($routeChangeSuccess 13 function( $currentRoute $previousRoute ) 13 $scopeaction = $routecurrentaction13 )13 $scopelogin = function() 13 do login and on success13 $locationpath(home)13 13 $scopeonSelectTree = function(treeID) 13 go fetch the tree using the treeID hellip 1313 myTree holds the tree13 $scope$broadcast(treeLoaded 13 myTree myTree13 )13 13 )13

myController

navigation directive

angularmodule(myApp)13 directive(navigation function() 13 return 13 restrict A13 scope 13 myTree =13 13 13 templateUrl 13 link function(scope) 13 scope$on(treeLoaded function() 13 makeTreeWith(scopemyTree) 13 13 13 13 )13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

But wait how does scopeonSelectTree work correctly when called in the menu

directive

26

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 62: Design strategies for AngularJS

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 63: Design strategies for AngularJS

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 64: Design strategies for AngularJS

indexhtml

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

27

ltdiv top-menu-view hellipgtltdivgt13 13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 65: Design strategies for AngularJS

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 66: Design strategies for AngularJS

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 67: Design strategies for AngularJS

ltdiv top-menu-view menu-data=menuData on-select-tree=onSelectTree(treeID)gtltdivgt13

menu directive

angularmodule(myApp)13 directive(topMenuView function() 13 return 13 restrict A13 scope 13 menuData =13 onSelectTree amp13 13 13 templateUrl 13 link function(scope) 13 scopechooseTree = function(tree)13 scopeonSelectTree(treeID treeid)13 13 13 )13

28

Pattern Pass Controller Functions as Directive

Attributes

indexhtml

ltbody ng-app=myApp ng-controller=myControllergt13 ltdiv id=homescopegt13 ltdiv class=rowgt

13 13 ltdivgt1313 13 ltdiv class=rowgt13 ltdiv id=leftPanelgt13 ltdiv nav-widget hellipgtltdivgt13 ltdivgt13 ltdiv id=middlePanelgt13 ltdiv workspace-contents hellipgtltdivgt13 ltdivgt13 ltdiv id=rightPanel gt13 ltdiv action-menu hellipgtltdivgt13 ltdivgt13 ltdivgt13 ltdivgt1313 hellip13ltbodygt13

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 68: Design strategies for AngularJS

Legacy ApplicationNon-JS MVC model and cannot make direct web calls from JS

to your application

Generate HTML stubs that invoke ldquowidgetsrdquo using directives

29smartorgdev

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 69: Design strategies for AngularJS

30

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 70: Design strategies for AngularJS

30

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 71: Design strategies for AngularJS

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 72: Design strategies for AngularJS

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 73: Design strategies for AngularJS

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 74: Design strategies for AngularJS

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 75: Design strategies for AngularJS

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 76: Design strategies for AngularJS

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 77: Design strategies for AngularJS

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

31

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 78: Design strategies for AngularJS

ltdiv id=mywidgetOuterDivgt ltdiv id=mywidget class= ng-controller=MyWidgetCtrlgt ltdiv mywidget-directive input-data=inputData setup-data=setupData()gt ltdivgt ltdivgtltdivgt

angularbootstrap($(mywidgetOuterDiv) [myApp])var scope = $(mywidget)scope()scopesetupData(APPmyWidgetConfig)

In your legacy web application render this html

In your JS code bootstrap your widget

widget directive

widget controller

widget container

and this JSjsCode = APPmyWidgetConfig = inputData hellip

Pattern Dynamically invoke angular application

31

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 79: Design strategies for AngularJS

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 80: Design strategies for AngularJS

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 81: Design strategies for AngularJS

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 82: Design strategies for AngularJS

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejs

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 83: Design strategies for AngularJS

angularmodule(myApp) controller(MyWidgetCtrl function($scope) $scopesetupData = function(myWidgetConfigMyWidgetConfig) if ($scopeinputData ampamp myWidgetConfig) addTablesConfig = windowstandalonemyWidgetConfig else if ($scopeinputData ampamp myWidgetConfig) return $scopeinputData = myWidgetConfiginputData ) directive(mywidgetDirective function() var templateUrl = pathtotemplatehtml if (windowproduction) templateUrl = localpathtotemplatehtml return restrict A templateUrl templateUrl scope inputData = setupData amp link function (scope elem attrs ctrl) )

Data made available to directive scope

standalonejsPattern

Standalone Widget Mode

32

Allows for standalone widget testing

windowstandalone = myWidgetConfig inputData hellip

standalone indexhtml

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 84: Design strategies for AngularJS

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

33smartorgdev

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 85: Design strategies for AngularJS

Old ideas like modularity once-and-only-once etc still apply

They just look different

34smartorgdev

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 86: Design strategies for AngularJS

Get expert help

35

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 87: Design strategies for AngularJS

Join us tomorrow for a Test-Driven Development session

1045 AM

Check us out at httprangalcom and httpsmartorgcom

36smartorgdev

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev

Page 88: Design strategies for AngularJS

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

Whatrsquos your AngularJS adoption experience

What have you learned

Write to usSomik Raha srahasmartorgcom

Kai Wu kwusmartorgcom

smartorgdev


Top Related