[go: up one dir, main page]

0% found this document useful (0 votes)
8 views44 pages

Angular

The document outlines best practices for managing code complexity through good organization, code reuse, and the Model-View-ViewModel (MVVM) architecture. It explains the roles of Model, View, and ViewModel in AngularJS, along with dependency injection and data binding techniques. Additionally, it covers AngularJS features such as filters, two-way binding, and the ng-repeat directive for dynamic content rendering.

Uploaded by

kiboame27
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views44 pages

Angular

The document outlines best practices for managing code complexity through good organization, code reuse, and the Model-View-ViewModel (MVVM) architecture. It explains the roles of Model, View, and ViewModel in AngularJS, along with dependency injection and data binding techniques. Additionally, it covers AngularJS features such as filters, two-way binding, and the ng-repeat directive for dynamic content rendering.

Uploaded by

kiboame27
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 44

MODULE 1

 Purpose of additional technology and approach is to deal with complexity not making the
code more complex
 Easier way to deal with code
 Good code organization
 Update functionality without a re-write of large portions of your code
 Code reuse( don’t re-write the same/similar code twice)
 Code should be easy to test(even small chunks of functionality)
 Why does code get complex
 Bad or inconsistent coding style
 Hard to read the variables and function name
 No comments or API documentation
 Lack of high cohesion and low coupling
o High cohesion- smaller pieces of functionality are strongly related to each
other within some code boundary and are less complex(tight coupling)
o Loose coupling- least possible dependency of one component to another
component/ change in one component doesn’t affect another component
e.g. one function does 3 fairly unrelated things(low cohesion webpage)
How to achieve high cohesion and loose coupling (mvvm)
Model-View-ViewModel
 Mode l- represent and holds raw data
 Some of this data in some form may be displayed In the view
 Contain logic to retrieve the data from some source
 Contain no logic associated with displaying the model, doesn’t know how to get
displayed or who’s going to display it
 View - user interface
 In the web app, it’s just the html and css
 Only displays the data that it is given
 Never changes the data just receive
 Declaratively broadcast events, but never handles them
 ViewModel - representation of the state of the view(backside)
 Holds the data displayed in the view
 Responds to view events e.g. presentation logic
 Calls other functionality for business logic processing
 Never directly asks the view to display anything, never manipulate the DOM
o Allows loose coupling because it never calls id’s in the html
 Declarative binder- binds the model of the viewModel to the view
 Declarative means you don’t have to write any code to bind them these is where
the framework does this magic
 Declarative binder is the key enabler of the MVVM pattern without it you will
have to write all the pattern by hand
 View(UI/Presentation) html css
 View Model(presentation logic) JavaScript
 Model(data/business logic) JavaScript
Js app
(function (){
'use strict';

angular.module('myFirstApp', [])

})();
 angular.module('myFirstApp', []) – takes the name of the application
and the list of indipandences in a form of an array<html ng-
app="myFirstApp"
<html ng-app="myFirstApp"
 ng-app – (angular application), we place it at an outer tag where we want it to be
responsible for
o from any it we named "myFirstApp" (<html>) to the end of the
tag(</html>) our angular application is responsible for it
 for a smaller position of code e.g div to be responsible for we use-
(function (){
'use strict';

angular.module('myFirstApp', [])

.controller('myFirstController', function (){

})

})();
 .controller – is the way we define the viewModule of the view
o Takes 2 things the name of the view module or controller and the function
 'use strict';- enable certain things to protect from making
mistakes
Sharing data with the view through scopes
 An object to share data between the viewModule and the view $scope
.controller('myFirstController', function ($scope){
 You can call a string
.controller('myFirstController', function ($scope){
$scope.name = "Tshepo"

<diV ng-controller="myFirstController" >


{{name}} // pop up in the web page
 Also call a function
.controller('myFirstController', function ($scope){
$scope.sayHello = function (){
return 'hello coursera' //{{sayHello()}}

 ng-model tells the value of the input element to be equal to it


<input type="text" ng-model="name">
Inside my input is: {{name}}
o textbox is equal ng-model="name"( tshepo ) every time you
change the name in the textbox it will also change in
the {{name}}
name calculator angularjs instead of js
(function(){
'use strict';

angular.module("nameCalculator", [])

.controller("nameCalculatorController", function($scope){
$scope.name = ""; // equal to the textbox/ displayed in the
textox
$scope.totalValue = 0;

$scope.displayNumeric = function(){
let totalNumericValue = calculateNumericString($scope.name);
$scope.totalValue = totalNumericValue
};

function calculateNumericString(string){
let totalStringvalue = 0;
for( let i = 0; i < string.length; i++){ //
totalStringvalue += string.charCodeAt(i) //
}
return totalStringvalue;
}

});
})()

Get an element attribute


<div class="target" ng-app="myTestApp" greetings="hello">
<section>Section 1
<article>article 1
</article>
</section>
</div>
let elm = document.querySelector('target')
/* var elm = document.getElementById('target')*/
console.log(elm) //show the whole <div></div>
including other elemenets within
the div//
console.log(elm.getAttribute('greetings')) //= hello

let elm2 = document.querySelector('[ng-app]')//only shows the element


called
console.log(elm2)

DEPENDENCY INJECTION(DI)
 design pattern that implements inversion of control(loC) for resolving dependencies
 during an payment process clients at called with the independency by some system
 the system is angularJS
 client is not responsible for instantiating the dependency
DI in javascript
function DIController ($scope, $filter){
 $filter let use create filtering functions that is used for formatting the data that get
displayed to a viewer
 $filter used the same way as $scope e.g
angular.module('DIApp', [])

.controller('DIController', DIController);

function DIController ($scope, $filter){


$scope.name = 'Tshepo'

$scope.upper = function(){ //upper is the function name


let upCase = $filter('uppercase') //’uppercase’ is the filter
we want
$scope.name = upCase($scope.name)// calling the variable
to .name

<diV ng-controller ="DIController" >


<input type="text" ng-model="name" ng-blur="upper();"> //ng-blur is
when the
Looses focus
</diV>
Protect dependency injection from minification

 Minification – is the process of removing of all unnecessary characters from source code
without changing its functionality
 Its is also uglfy it uglyfies the code
 Removes wide space characters, comments , new line characters etc
 Purpose of it is not reduce the amount of data transferred from server
 During manification ($scope, $filter) are the names that angular must
look
for in order to inject to the DIcontroller
 DI in angular need to be manification proof
 To fix you can
1. (a) In the .controller function the 2nd argument is a function in can be an
array [or in line array with function as last element
.controller('DIController',
['$scope','$filter',DIController]);
(b)
.controller('DIController', ['$scope','$filter',
function($scope, $filter){

$scope.name = 'Tshepo'

$scope.upper = function(){
let upCase = $filter('uppercase')
$scope.name = upCase($scope.name)
}

o This is not advicable because it Is illegal javascript readability


2. Best one – attach $inject property to the function object
.controller('DIController', DIController);

DIController.$inject = ['$scope', '$filter'];

Manificated version of it
!function(){"use strict";function e(e,n)
{e.name="Tshepo",e.upper=function(){let o=n("uppercase");
e.name=o(e.name)}}angular.module("DIApp",
[]).controller("DIController",e),e.$inject=["$scope","$filter"]}()

Expressions & interpolation


 Expression: {{ exp }} – something that evaluate to some value
 They are processed by angular
 Executed in the context of the scope and has access to properties on $scope
 Doesn’t throw an error if it result in a type error or reference error it simply
display an empty string or value
 Control flow functions ( e.g if statements… ) are not allowed inside expression
 Accept a filter or a filter chain to format the output
 Interpolation: process of evaluating a string literal containing one or more placeholders,
which are replaced with values e.g
In Angular, this string:
Message is {{ message }}
(Provided message = “ hello “ ) is interpolated in the string
Message is hello
 Still connected to the original message property that Is sitting in the scope
o if $scope.message changes so will the interpolation result
<diV ng-controller ="MsgController" >
{{name}} has a message for you: <br>
{{sayMessage()}}

function MsgController($scope){
$scope.name = 'tshepo';

$scope.sayMessage = function(){
return 'Tshepo likes to eat healthy snacks'
}
}

Example 2
<button ng-click="feedTshepo()">Feed Tshepo</button>
<br>
<img ng-src="img/young-man-{{stateOfBeing}}.webp">
</div>

MsgController.$inject =['$scope'];
function MsgController($scope){
$scope.name = 'tshepo';
$scope.stateOfBeing = 'hungry'

$scope.sayMessage = function(){
return 'Tsepo likes to eat healthy snacks'
}
$scope.feedTshepo = function(){
$scope.stateOfBeing = 'fed'
}
 use ng-src=”” because we only want the image to be fetched when angular got uphold
to it.
 ng-click=””

MODULE 2
Filters
 change the output of an expression
 you can do that either on javascript or html

filters in javascript
const output =
$filters(‘uppercase’)(value)

Filters in html
{{ “Hello” | uppercase }}
“hello” can either be $scope.value
$scope.sayMessage = function(){
let name = 'Tshepo likes to eat healthy snacks'
let msg = $filter('uppercase')(name)
return msg // name will be in uppercase
 under angulajs website there are a lot of different built in-filters and other built-in
components e.g currency, number, date , JSON
currency

in html
{{ currency_expression | currency : symbol : fractionSize }}
In javascript
$filter(‘currency’)(amount, symbol, fractonSize )
 fractionSize is 0.00 or .000
 symbol – dollar or yen or euro or rand sign

custom filters
 creating our own custom filters
 there are steps to create it –
1. define filter factory function
function customFilterfactory(){
return function(){
// change input
return changed input
 customFilterFactory this function creates and return our filter function

2. register filter factory with module


angular.module( ‘app’, [] )
.controller( ‘Ctrl’, Ctrl )
.filter( ‘custom’, customFilterfactory )
3. inject it with nameFilter (e.g customFilter )
Ctrl.$inject = [ ‘$scope’ , ‘customFilter’ ]

Function Ctrl ($scope , customFilter ){


Let msg = ‘some input’
customFilter(msg )

2-way, 1-way & 1-time binding

2 way binding

Your name:
<input type= ‘text’ ng-model=’name’>

1 way binding

<div> Ech: {{last name}} </div>

Ng-repeat

<ul>
<li ng-repeat="item in shoppingList1"> {{item}} </li>
</ul>
 <ul></ul> - annotated list
 Ng-repeat – is similar to a for each loop
 Item in shoppingList1 – means we are going to loop over shoppingList1 array
and each through interaction the item of the collection will be equal to the
item variable
o If you don’t write item in an error will occur
 {{item}} – interpolating the item as the value of the body of the <li> tag
<ul>
<li ng-repeat="item in shoppingList2"> {{$index + 1}}. Buy
{{item.quantity}} of {{item.name}}(s) </li>
</ul>

 {{$index + 1 }} – shows each item numerical instead of bullet points


 Index start from 0 so +1 it will start counting from 1
<input type="text" ng-model="shoppingList2[0].quantity">
 [0].quantity –the 1st index while watching the quantity. By default in the
textbox the value that occurs is 2 so when you change the value in the textbox
the value changes as well

If you want to add a new item


(function (){
'use strict';

const shoppingList2 = [
{
name: "Milk",
quantity: "2"
},
{
name: "Donuts",
quantity: "200"
},
{
name: "Qookies",
quantity: "300"
},
{
name: "Peanut Butter",
quantity: "5"
}
]
angular.module('shoppingListApp', [])
.controller('shoppingListController', shoppingListController);

shoppingListController.$inject = ["$scope"]
function shoppingListController($scope){
$scope.shoppingList1 = shoppingList1;
$scope.shoppingList2 = shoppingList2;

$scope.addToList = function(){
const newItem = {
name: $scope.newItemName ,
quantity: $scope.newItemQuantity
};
$scope.shoppingList2.push(newItem)
}
}

})()

<input type="text" ng-model="shoppingList2[0].quantity">


<ul> <li ng-repeat="item in shoppingList2"> {{$index + 1}}.
Buy {{item.quantity}} of {{item.name}}(s) </li>
</ul>
<input type="text" ng-model="newItemName" placeholder="item name">
<input type="text" ng-model="newItemQuantity" placeholder="item
quantity">
<button ng-click="addToList()">Add To List</button>

Filter ng-repeat
 Array have a specific function called filter
 Creates new array where each item satisfies some condition of comparison
function passed into the filter function
 Angular has a specific filter called filter
 Provided a string as 1st argument, it will filter the array applied to it. Matching
all string item against the provided one
 We apply it using – ng-repeat=”item in collect | filter : searchString”
const numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log("Number array: ", numberArray)

let filterNumberArray = numberArray.filter(function(value){


return value > 5;
});
console.log("Filtered number array: ", filterNumberArray)// 6, 7, 8, 9,
10 appear

or
const numberArray = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
console.log("Number array: ", numberArray)

function above5filter(value){
return value > 5
}
let filterNumberArray = numberArray.filter(above5filter)
console.log("Filtered number array: ", filterNumberArray)
 The value(parameter) will be equal to each item in numberArray
 Searching for an item in the shopping list(angular)
const shoppingList1 = [
"Milk", "Donuts", "Cookies", "Chocolate", "Peanut Butter",
"Pepto Bismol",
"Pepto Bismol (Chocolate Flavour)", "Peptom Bismol {cookie
Flavour}"
];

let searchList = "Bismol"


function containFilter(value){
return value.indexOf(searchList) !== -1;
}
const searchedShoppingList = shoppingList1.filter(containFilter)
console.log("searched shopping list: ", searchedShoppingList)
 return value.indexOf(searchList) !== -1;
o !== -1 means that the searchList is part of the string of were the value will
be. And value is one item inside
o Every item with the word “bismol ” will appear in the webpage

 Searching for an item in angular js using the item list


<input type="text" ng-model="search">
<ul>
<li ng-repeat="item in shoppingList | filter : search">
{{item}} </li>
</ul>

 The filter uses the search string to figure out weather the item in the
shoppingList array matches the search string. But since we are updating the
search string using the 2 way binding(ng-model = “search”) the ng-repeat get
filtered on the fly(automatic)

Controller AS Syntrax: Prototypal Inheritance


 Inheritance- is when an object or a class is based on another object or a class(parent),
using the same implementation and/or same values

e.g animal dog


numberOfLegs numberOfLegs
walk() walk()
 Dog class has access to/ has inherited the numberOfLegs and
walk method from the animal
 This technique is used for code reuse as well as logical entity structure

Js Prototypal inheritance
 Unlike object oriented inheritance which is based on classes and more complex and has
so much rules. Prototypal inheritance is based on object instance and simple and straight
forward

Parent <---------- child(created based on parent)


Type: “parent” prototype chain
{}
Method()

 Child.type – javascript will look into child object and look


for .type since theres no value javascript engine will look to
the prototype chain to see which object is the parent of the
child object therefore child.type = “parent”
 Prototype chain- is not only limited to one object(child) it can
have great children and so forth
o Means the parent will be the grandparent and child will
become a new parent and set a type property on the
child(new parent)

Child
Type= “child” type of the parent will be
masked by the new type

Parent to child
const parent = {
value : "parentObject",
obj: {
objValue : "parentObjValue"
},
Walk: () => {
console.log("walking!")
}
}

let child = Object.create(parent);


console.log("CHILD - child.value: ", child.value);
console.log("CHILD - child.objValue: ", child.obj.objValue)
console.log("PARENT - parent.value: ", parent.value)
console.log("PARENT - parent.obj.objVAlue: ", parent.obj.objValue)
console.log("parent: ", parent);
console.log("child: ", child)
 The JavaScript engine will look and went up to the prototype chain to look
.value/.objValue etc
 (“child”, child) – does not have an output value but have
_ptototype_ value:parentValue
Parent(child) to child(grand-child)
child.value = "childValue"
child.obj.objValue = "childObjValue"
console.log("*** CHANGED: child.value = 'childValue'")
console.log("*** CHANGED: child.obj.objValue = 'childObjValue'")
console.log("CHILD - child.value: ", child.value);
console.log("CHILD - child.objValue: ", child.obj.objValue)
console.log("PARENT - parent.value: ", parent.value)
console.log("PARENT - parent.obj.objVAlue: ", parent.obj.objValue)
console.log("parent: ", parent);
console.log("child: ", child)

console.log("child.obj === parent.obj ? ", child.obj === parent.obj) //


yes

 Javasrcipt engine will not access the parent.value property it will


access the child.value property because the child ls masking the
parent property
 Child.objValue === parent.objValue
 (“child: ”, child) is now equal childValue
Scope inheritance
<div ng-controller=’controller_1’> - outer controller
<div ng-controller=’controlle_2’>
<div ng-controller=’controller_3’>’
 The scope of the inner controller inherit the scope from the outer controller
 When you change property of an inherited object we change also the original
source(parent)
 All controller reflect the change and no masking occur
 Controller as syntax – provide a convenient object used to attach all of our property to, so
that property masking doesn’t get in a way

<div ng-controller=’controller1 as ctrl1’> - $scope.ctrl1


<div ng-controller=’controller2 as ctrl2’> - $scope.ctrl2
 Angular creates a property label(ctrl1 or ctrl2) on the $scope( $scope.ctrl1)
o The label becomes a reference to this – instance of the controller
i. It works because labelController treats it as a function
constructor and you attach properties to ‘this’ inside of
controller not $scope
parentController1.$inject = ["$scope"];
function parentController1($scope){
$scope.parentValue = 1;
$scope.pc = this;
$scope.pc.parentValue = 1;
}

childController1.$inject = ['$scope']
function childController1($scope){
console.log("$scope.parentValue: ", $scope.parentValue)
console.log("CHILD $scope: ", $scope)

 _proto_ - on the prototype in scope of the child, the parentValue of the child = 1. Directly
on the child scope parentValue is not available
$scope.parentValue = 5;
console.log("$*** CHANGED: $scope.parentValue = 5 ***")
console.log("$scope.parenrValue: ", $scope.parentValue )
console.log($scope)
}
 parentValue = 5 because the current parentValue belongs to the child controller
 on the child scope the is directly a parentValue = 5. On the _proto_ the parentValue we
used before is still =1, because the child controller scope is masking the parentValue
property

console.log("$scope.pc.parentValue: ", $scope.pc.parentValue)


$scope.pc.parentValue = 5;
console.log("$*** CHANGED: $scope.parentValue = 5 ***")
console.log("$scope.parenrValue: ", $scope.pc.parentValue )
console.log($scope)

 $scope.pc – traverse the prototype chain to the parent object which means if you change the
parentValue ( $scope.pc.parentValue = 5; ) it will not only change the child value it will also change
in its roots the parentController1

Controller as syntax
parentController2.$inject = ['$scope'] //not need because we are
attaching the
property directly to the
controller
function parentController2(){
let parent = this;
parent.value = 1;
}
ChildController2.$inject = ['$scope']
function ChildController2($scope){
const child = this;
child.value = 5;
console.log("ChildController $scope: ", $scope)
}

 Since .value is assigned to the controllers of both child and parent properties the
child.value= 5 will not mask parent.value = 1
 If you reference a proper controller .value can work independently
<div ng-controller="parentController2 as parent">
Parent value: {{parent.value}}

<div ng-controller="childController2 as child">


Child value: {{child.value}}
Parent value: {{parent.value}}
</div>
o Can now reference properties of the parent to the inner child
controller

Custom servives
Controller responsibility –
 Use controllers to
 Set up the Initial state of $scope
 Add behavior to the $scope
 Do not use controllers to
 Handle business logic directly
 Share code or state across controllers
 Share data across components
Register service function constructor
Angular.module(‘app’, [])
.controller(‘ctrl’, ctrl)
.service(‘customService’, customService)
 ‘customService’ – the string name you give to the service is used
to inject into other services or controllers not the name of the
function that is used a function constructor to create the service
 .service(‘name’, function)-
 The function you supply to the .service e.g customService will be
treated as a function constructor
o Means the angular js internally will new up your function
using a new keyword which has a ramification for what
this keyword means inside your service function
let itemAdder = this;
 Singleton design pattern-
 Restricts object to always having a single instance
o Each dependent component gets a reference to the
same instance
o Multiple controllers injected with a service will all have
access to the same service instance
 Lazily instantiated-
 Only created if an application component declares it as a
dependency
o If no component in your application are dependent on this
service it will never get created
<div ng-controller="shoppingListAddController as itemAdder">
<input type="text" ng-model="itemAdder.itemName"
placeholder="item name">
<input type="text" ng-model="itemAdder.itemQuantity"
placeholder="quantity">
<button ng-click="itemAdder.addItem();">Add Item To Shopping
List</button>
</div>

 itemAdder- is used add items to the shopping list


<div ng-controller="shoppingListShowController as showList">
<ol>
<li ng-repeat="item in showList.items">
{{item.quantity}} of {{item.name}}
</li>
</ol>

 these are two controllers data cant be passed to one another


custom services with .factory()
 factory design pattern-
 central place that produce new objects or function
o produce any type of object, not just a singleton
o produce dynamically customizable services
 .factory() is not just another way of creating the same service, you can create
with .service() but it can be
 .service()is also a factory, but a much more limited one compared to .factory(). It’s a
factory that always produce the same type of service. A singleton, without an easy way to
configure its behavior

Angular.module(‘app’, [])
.controller(‘ctrl’, ctrl)
.factory(‘customService’, customService)
 customService the function that is expected to produce a service
 .service() – the customService the function is expected to be the service
 ‘customService’ – whats injected

Factory function

function customService(){
const factory = () => {
return new someService();
};
return factory;
}

 We want to create someService, to call new because we decide what gets created or not
then we return that

Custom services with .provider()


Step 1
Provider.$get = () => {
Let service = new service(provider.config.prop);
Return service
}
 Provider.$get- is a function that is attached to the provider. That function is a factory
function
Step 2- register provider function
Angular.module(‘app’, [])
.controller(‘ctrl’, ctrl)
.provider(‘Service’, ServiceProvider)
 ‘service’- name of service as it will be injected into other services,
controllers
 ServiceProvider – name of the function does doesn’t matter
Step 3-inject it
Ctrl.$inject = [‘$scope’ , ‘Service’]
Function ctrl($scope, Service){
Service.someMethod()}
 Inject with .provider defined name
Step 4 – register config
Ctrl.$inject = [‘$scope’ , ‘Service’]
Function ctrl($scope, Service){
Service.someMethod()}
.config(Config)
 Config guaranteed to run before other services, factories and controllers
Config.$inject = ['shoppingListServiceProvider'];
function Config(shoppingListServiceProvider){
shoppingListServiceProvider.defaults.maxItem = 2
}
 Max items will no longer be (10) it will be (2) even though there
is code for it. More of a shortcut after the initial code
 Cant inject regular components into .config
 We can inject the provider of service with nameProvider
Ng-if , ng-show and ng-hide

 Ng-if
<div class="error" ng-if="list2.errorMessage">error:
{{ list2.errorMessage }}</div>
</div>
 Ng-if takes a condition as its value, if there condition is true the
entire div is shown if the condition is false, angular takes the
entire div out of the dom tree
 E.g on the shopping cart list, the div is not existing(false)
because maximum items(10) haven’t been reached
 Ng-show
<div class="error" ng-show="list2.errorMessage">error:
{{ list2.errorMessage }}</div>
</div>
 Has a class ng-hide in console.log that display: none when you
reached maximum the ng-hide disappears and get displayed on
screen as error: max item(5) reached
 Ng-hide
<div class="error" ng-hide="!list2.errorMessage">error:
{{ list2.errorMessage }}</div>
</div>
 Opposite of ng-show(vise versa) for ng not to display reaching
max item before adding items you must include ! on ng-hide=””
ANGULAR JS AND NEW ES6 API
 Before promise the were callbacks
 Callbacks were hard to read
 They couldn’t be executed in parallel and did not display an error
asyncFunction1(function (){
asyncFunction2(function (){
asyncFunction3(function (){
})
)}
)}
 Promise – object which can be passed around or returned that holds references to the
outcome of asynchronous behavior
 Give us a lot of flexibility when dealing asynchronous behavior
 In angular promise API are created through the $q service
 Promises either get resolved of rejected
 The ‘ then‘ method takes 2 arguments(both are functions) –
1. Function that handle success or resolve outcome
2. Function to handle error or reject outcome
 Then itself returns a promise sot its chainable
Angularjs $q service promise
2nd- step
function asyncFunction (){
let deferred = $q.defer()
if(…) { deferred.resolve(result) }
else { deferred.reject(error) }
return deferred.promise;
 $q.defer() Creates objects that a async environment with all the hooks into it, including
the promise object
 .resolve marks a successful completion of our execution, then wraps the data for the
promise
 .reject If something goes wrong marks a unsuccessful completion , then wraps the data
for the promise
 return deferred.promise; Return the promise to the caller (a hook back to the entire
process)
1st- step
let promise = asyncFunction()
promise.then(function (result){
}
Function(error){
}).then(…)
 next step is for the caller to call the asynchronous function and call a reference to the
promise object let promise. then when the application is appropriate, you call the then
function on the promise to extract the result or the error promise.then which are
functions themselves
 if there are more than one promises
3rd-step
$q.all([promise1, promise2])
.then(function(result){
})
.catch(function(error){
})
 $q.all – allow us to execute multiple promises in parallel, handling success/fail in
one place
e.g
2nd -step
shoppingListService.$inject = ['$q', 'weightLossFilterService']
function shoppingListService($q, weightLossFilterService){
let service = this;

// List of shopping items


const items = []

service.addItem = (name, quantity) => { addItem is using a asynch


behaviour
let promise = weightLossFilterService.checkName(name);
checks the name if we are allowed to put in it
promise.then(function (response){
let NextPromise =
weightLossFilterService.checkQuantity(quantity)
before the response is used the nextPromise gets
executed
NextPromise.then(function (result){
const item = {
name: name,
quantity: quantity
}; nextPromise will call .then function again and if
everything
items.push(item)is checking out the (new) item gets
pushed(items)
}, function(errorResponse){
console.log(errorResponse.message)
});if nextPromise fails error message is displayed in console
}, function(errorResponse){
console.log(errorResponse.message)if promise fails message
displayed
});
};
1st-step
weightLossFilterService.$inject = ['$q', '$timeout']
function weightLossFilterService($q, $timeout){
let service = this;

service.checkName = (name) => {


let deferred = $q.defer(); //checkName acquire the deferred
object of asy

const result = {
message: ""
}

$timeout(function(){
//check for cookies
if(name.toLowerCase().indexOf('cookies') === -1){
deferred.resolve(result)
}
else{
result.message = "Stay away from cookies, Tshepo";
deferred.reject(result)
}
}, 3000);

return deferred.promise
}

service.checkQuantity = (quantity) => {


let deferred = $q.defer();
const result = {
message: ""
};

$timeout(function(){
if(quantity < 6){
deferred.resolve(result)
}
else{
result.message = "That's too much, Tshepo";
deferred.reject(result);
}
}, 1000)
return deferred.promise returned back to have the hook for the
hook
}
 $timeout – is similar to setTimeout in javascript but angularised
 Name is lowercased name.toLowerCase(). and the word cookie will be checked if it is
not there indexOf('cookies') === -1
 If not, it will be successful(.resolve) with the result being an empty string
deferred.resolve(result)
 Else if the word cookie is there it will be unsuccessful(.reject)
deferred.reject(result) and a message will be displayed in the empty
string result.message = "Stay away from cookies, Tshepo

Since the is more than one promise the 2nd step can be void and do the 3rd
shoppingListService.$inject = ['$q', 'weightLossFilterService']
function shoppingListService($q, weightLossFilterService){
let service = this;

// // List of shopping items


const items = []

service.addItem = function (name, quantity){


let namePromise = weightLossFilterService.checkName(name);
let quantityPromise = weightLossFilterService.checkQuantity(quantity)

$q.all([namePromise, quantityPromise]).
then( function (response) {
const item = {
name: name,
quantity: quantity
}
items.push(item)
})
.catch( function(errorResponse){
console.log(errorResponse.message)
})
}

service.removeItem = (itemIndex) => {


items.splice(itemIndex, 1)
};

service.getItem = () => {
return items
}
}

Ajax with $http service


 Is to make the communication between the front-end application and the server simple
and straight forward
 Since the http service is in its essence asynchronous, its based in the deferred and
promise API exposed by the $q service
$http({
Method: “GET”,
url: “http://someurl”,
params: { param1: “value1”}
}).then(…)
 ‘url’ is the only required property
Directives: Dynamic HTML
 Why angular? In term of directives-
 HTML is great for declaring static documents, but if falters when we try to use it for
declaring dynamic views in web application. Angular lets you to extend HTML
vocabulary for your application .The resulting environment is extraordinary
expressive, readable, and quick to develop.
Directives
 Marker on a DOM element that tells Angular’s HTML compiler to attach a specified
behavior to that DOM element
 The complier can even transform/change the DOM elements and its children
 A marker can be an attribute, elements name, comments, or CSS class
Step – 1 step – 2
step - 3
Angular.module(‘app’, []) myTag.$inject = []
<my-tag></my-tag>
.controller(‘myCtrl’, myCtrl) function myTag(){
.directive(‘myTag’, myTag) let ddo = {
Template: ‘Hello
World’
}
}
return ddo
o ‘myTag’ – normalized name that will appear in HTML
o myTag – factory function-return DDO(Directive Definition Object)
o return ddo – ddo must be returned

.directive('listItemDescription', listItemDescription)

function listItemDescription(){
const ddo = {
template: '{{ item.quantity }} of {{ item.name }}'
};
return ddo;
}
 register name of directive you must use camelCase
.directive('listItemDescription'
 when calling it, you use kabab-case <list-item-description></
<list-item-description></list-item-description>

 if the is a large string you use templateURL –


 templateUrl allows you to point to the HTML template/file, place the entire
template into that file
.directive('listItem', listItem)

function listItem(){
const ddo = {
templateUrl : 'listItem.html'
}
return ddo
}
 listItem.html – newly created file that templateUrl points to
<ol>
<list-item ng-repeat="item in list.items"></list-
item>
</ol>
 on the <list-item> tags its optional to write the ng-repeat there can be written in
the main file.
 We use these to avoid code duplication

Directives: Restrict Property


 Tell the angularjs complier where to detect your custom directive, try to detect it as a
attribute to a different element or should look for an element with the name of the
registered directive
 If you do not specify the restrict property on the ddo, angular will default its value as AE
 A- attribute
 E- element
 Best practice to restrict to attribute(A) if directive is extending behavior( e.g ng-repeat)
 Best practice to restrict to element(E) if directive is defining a component with an
associated template(e.g <list-item>)

function listItem(){
const ddo = {
restrict: "AE",
templateUrl : 'listItem.html'
}
return ddo
}

 If we restrict it to A – on list2 nothing will be displayed because list2 is an element not a


attribute but the <li> tags on the list-item file must be removed because it will cause a
confliction whereby a single item will have double digits since there will be 2 <li>
<li list-item ng-repeat="item in list.items"></li> //changed
 If we restrict it to E – on list1 nothing will be displayed because list1 it’s a attribute not a
element but the <li> tags on the list-item must remain since an elements require tags
<list-item ng-repeat="item in list.items"></list-item>

Directive’s isolate scope “ = ” and “ @ “


<div id="list1" ng-controller="shoppingListController1 as list">
 Since the are two list, it will be best to specify which list from the controller as syntax as
a list1 and list2
<button ng-click="list.removeItem($index)">Remove
Item</button>
 But on the ng-click list ng-click="list.removeItem($index) is not equal to
list1 and list2 so the delete button will not work until you change the list ng-
click="list1.removeItem($index)(on list1 the delete button
will work not on list2) or ng-click="list.removeItem($index)
( on list2 the delete button will work not on list1)
 To fix it you must re-artitecture our custom directive such that Its functions works
independently from its environment and have the environment pass certain values into it
 We can do that using isolate scope
 Scope of a parent is the scope of the directive, we need to break away from the
inheritance and create an isolated scope for the directive
 Bidirectional binding (‘=’) is such that directive scope property change effects the bound
property and visa versa
 DOM attribute value binding (‘@’) always results in directive property being a string
 Changes to DOM attribute value are propagated to the directive property, but not
the other way around

Function myDirective(){
Let ddo = {
Scope: {
MyProp: ‘=attributeName’}
}
}
Return ddo
}
<shopping-list my-list="list1 " title="{{list1.title}}"></shopping-list>

.directive('shoppingList', shoppingList)
function shoppingList(){
const ddo = {
templateUrl: 'shoppingList.html',
scope: {
list: '=myList',
title: '@title'
}
}
return ddo;
}

<h3>{{ title }}</h3>


<ol>
<li ng-repeat="item in list.items">
{{ item.quantity }} of {{ item.name }}
<button ng-click="list.removeItem($index)">Remove Item</button>
</li>
</ol>

let origTitle = "Shopping List #1"


list.title = origTitle + " ( " + list.items.length + " items )"
 When adding, the item text origTitle + " ( " + list.items.length + " items
) " on the list increases as you increase items shopping cart
Using controllers inside directives
 to add functionality to the directive, one choice is to use a controller that’s declared
directly on the DDO
 use bindTocontroller
Function myDirective(){ controllerFunction =
[‘Service’]
Const ddo = { function
controllerFunction(Service){
Scope: { let myCtrl = this;
Prop: ‘=’ myCtrl.method =
function(){
} let name = “
Hello ” + myCtrl.prop
Controller: controllerFunction,
bindToController: true,
controllerAs: ‘myCtrl’,
templateUrl: ‘template.hml’
}
 ‘=’ bidirectional binding – both parent and property of directive are watch for changes
 If we have no plans of changing the bound value inside the directive, we use one-way
binding
 ‘<’ one-way binding – watches only the identity of the parent property, not the
property inside directive
 Use bindToController and controllerAs to bind declared properties in isolate scope
directly to controller
function shoppingListDirective(){
const ddo = {
templateUrl: 'shoppingList.html',
scope: {
items: '<',
title: '@'
},
controller: shoppingListDirectiveController
controllerAs: 'list',In shoopinglist.html refer to
controller through label list that’s where items and title will show
up
bindToController: true binding the scope variables items &
title
}
return ddo;
}
 After this you implement the controller function as usual

Directive APIs and ‘&’


Function controller(){
this.method = function(arg1){
this.prop = “Hi” + arg1

Function myDirective(){ <div ng-controller= ‘controller as ctrl>


Let ddo = { <my-directive
Scope: { method=”ctrl.method(myArg)”>
myMethod: ‘&method’ </my directive>
} </div>
templateUrl: ‘template.html’
} <button ng-click=”dirCtrl.myMethod({myArg:
‘v1’})”>remove item
Return ddo </button>

 this - refers to the parent controller instance


 arg1 – needs to come from child directive
 myMethod – property name to reference to pass method that exist on the parent controller
scope
 &method – attribute name use in parent template on this directive
 (myArg) – is a key which we later use to assign something from the directive isolate
scope, we are not actually passing the myArg from the controller to the my-directive
 myMethod – method name from isolate scope mapping
 ({myArg: ‘v1’})”> use the name of the argument that parent made a call with and
mapping some value to it from the directive
* displaying the item removed when we delete an item
function shoppingListDirective(){
const ddo = {
templateUrl: 'shoppingList.html',
scope: {
items: '<',
myTitle: '@title', only focus on changes happening in the
title
badRemove: '=', bidirectional binding
onRemove: '&' reference binding

},
list.removeItem = (itemIndex) => {
this.lastRemoved = "Last item removed was " +
this.items[itemIndex].name
saving the array in the last remove property
shoppingList.removeItem(itemIndex);
list.title = origTitle + " ( " + list.items.length + " items )"
};
}

<span>{{ list.lastRemoved }}</span> output what has been removed

<shopping-list
items="list.items"
title="{{list.title}}"
bad-remove="list.removeItem" passed a function of removing
item
on-remove="list.removeItem(index)"> index for mapping
</shopping-list>
 list.removeItem(index)"> -this (index) is not passed by shoppingListController as
list, these index is just a key for our directive to be able to find
<h3>{{ list.myTitle }}</h3>
<ol>
<li ng-repeat="item in list.items">
{{ item.quantity }} of {{ item.name }}
<button ng-click="list.badRemove($index)">Bad Remove
Item</button>
<button ng-click="list.onRemove({index: $index});">Remove
Item</button>
</li> index that I mapped is = to $index when clicking
</ol>
<div class="error" ng-if="list.cookiesInList()">WARNING! WARNING! COOKIES
DETECTED!</div>

Manipulating the DOM with link


Function MyDirective (){ function linkfunction(scope,
element, attrs, controller){
Const ddo = { }
Scope: { --- }
Link: linkFunction,

templateUrl: ‘template.htm’
}
 manipulating the dom with link we actually manipulated the error warnings when typing
cookies in the cart
MODULE 4
Components & Component-based architecture
 components – is a special kind of directive that use a simplified configuration that assume
some default
 while components don’t restrict you to component based architecture, using components
makes it easier or more natural to structure you code
 components only control their own View and data
 they never modify data or DOM outside their own scope, they use isolate scope
 components have well-defined public API- inputs and outputs
 inputs: use ‘<’ and ‘@’ binding only
 never change property of passed in object or array
 output: use ‘&’ for component event callbacks
 pass data to callback through param map { key: val}
 components have well-defined lifecycle
 $oninit – controller initialization code
 $onChanges(changeObj) – called whenever one-way binding are updated
o Current value- (changeObj.current value) and previous value
(changeobj,previousValue)
 $postLink – similar to ‘link’ in directive
 $onDestroy- when scope is about to be destroyed
 Application is a tree of components
 Entire application could be comprised components
 Each one would have a well-defined input and output
 2-way binding is minimized as much as possible
Angular.module(‘App’, []) <div
.component(‘myComponent’, { ng-
click=”$ctrl.onAction({myArg: ’val‘}) ”>
templateUrl: ‘template.html’, {{ $ctrl1.prop1.prop }}
and {{ $ctrl1.prop2 }}
controller: CompController, </div>
binding: {
prop1: ‘<’ <my-component
prop2: ‘@’ prop1= “val-1”
onAction: ‘&’ prop2=”@parentProp”
} on-action=
“parentFunction(myArg) ”
}) {{ $ctrl1.prop1.prop}} and
{{ $ctrl1.prop2 }}
 ‘myComponent’ - normalized form. In Html, use my-component
 CompController,- not required to specify unless you want to add
functionality to it
 Angular will provide an empty object automatically onto the isolate scope($ctrl)
 ‘bindings’ – object is the isolate scope param mapping defination

angular.module('ShoppingListComponentApp', [])
.controller('shoppingListController1', shoppingListController1)
.factory('shoppingListFactory', shoppingListFactory)
.component('shoppingList', { instead of directive we are using
component
templateUrl: 'shoppingList.html',
controller: shoppingListComponentController,
bindings: { bindings = scope
items: '<',
myTitle: '@title',
onRemove: '&'
}
})
// function shoppingListDirective(){
// const ddo = {
// templateUrl: 'shoppingList.html',
// scope: {
// items: '<',
// myTitle: '@title',
// onRemove: '&'

// },
// controller: shoppingListDirectiveController,
// controllerAs: 'list',
// bindToController: true
// }
// return ddo;
// }

function shoppingListComponentController(){it was


shoppingListDirectiveController
let $ctrl = this; on $ctrl you can use any variable you want ‘let why
= this‘
$ctrl.cookiesInList = function (){
for(let i = 0; i < $ctrl.items.length; i++){
let name = $ctrl.items[i].name;
if( name.toLowerCase().indexOf("cookie") !== -1){
return true;
}
}
return false;
}
$ctrl.remove = function(myIndex){use these to make it more cleaner in
html
$ctrl.onRemove({index: myIndex})
<h3>{{ $ctrl.myTitle }}</h3>
<ol>
<li ng-repeat="item in $ctrl.items">
{{ item.quantity }} of {{ item.name }}
<button ng-click="$ctrl.remove($index);">Remove Item</button>more
cleaner
</li>
</ol>
<div class="error" ng-if="$ctrl.cookiesInList()">WARNING! WARNING!
COOKIES DETECTED!</div>

$ctrl.$postLink = function(){
$scope.$watch('$ctrl.cookiesInList()', function(newValue ,
oldValue){
console.log($element)$watch-will watch($ctrl.cookiesInList()) and
watch
if(newValue === true){ it with newValue and oldValue
//show warning
let warningElem = $element.find('div.error');
warningElem.slideDown(900)
}else{
//hide warning
let warningElem = $element.find('div.error')
warningElem.slideUp(900)
}
})
}
 Avoid using $scope

$ctrl.$doCheck = function(){
if($ctrl.items.length !== totalItems){
console.log("# of items change. Checking for cookies!")
totalItems = $ctrl.items.length
if($ctrl.cookiesInList()){
let warningElem = $element.find('div.error');
warningElem.slideDown(900)
}
else{
let warningElem = $element.find('div.error')
warningElem.slideUp(900)
}
}
}
}

AngularJS event system


 Communicate parent scope - $scope.$parent
- use &method callback binding
 Communicate child – provide a way to send date into it and able to react to the new data
 Communicate grandchild – $scope.$parent.$parent
 When having multiple generations it becomes harder to communicate
 Angular has a solution for these which is publish-subscribe design pattern
Publish-subscribe design pattern
 Publishers send messages to subscribers on a common channel
 Publishers:
- Mark messages with a classification
- Don’t know subscribes or if there are any
 Subscribes:
- Sign up to listen for messages with a particular classification
- Don’t know publishers or if there are any
 In angular, the common channel is scope
 Messages are events that can hold data
 2 types of publishers- e.g event(‘greet’, {msg.Hi}
- $scope.$emit- up scope chain(start from the grandchild- to-parents-to-
grandparents)
- $scope.$broadcast- down scope chain(start from grandparent-to-parent-child)
 To subscribe to an event - $scope.$on(‘greet’, handlerFunction)
 What will happen if the target of your broadcast is not in the direct path of your broadcast
code down the chain
 Broadcast the event from the parent scope of everything in your app e.g
html(ng-app) also known as a root scope
o html(ng-app) - Parent controller to all control that all live under it
o to refer to the highest scope in the chain we use $rootScope
 so if you are trying to reach a target that Is not in the direct path we use
$rootScope.$broadcast
$scope.$emit(
‘namescpace: eventName’,
{prop: value})

$scope.$on(‘namespace:eventName’, handler)
Function handler(event, data)[
If(data.prop === ‘val1’){
}
ShoppingListComponentController.$inject = ['$rootScope', '$element',
'$q', 'WeightLossFilterService']
function ShoppingListComponentController($rootScope, $element, $q,
WeightLossFilterService) {
var $ctrl = this;
var totalItems;

$ctrl.$onInit = function () {
totalItems = 0;
};

$ctrl.$doCheck = function () {
if ($ctrl.items.length !== totalItems) {
totalItems = $ctrl.items.length;

$rootScope.$broadcast('shoppinglist:processing', {on: true});


var promises = [];
for (var i = 0; i < $ctrl.items.length; i++) {

promises.push(WeightLossFilterService.checkName($ctrl.items[i].name));
}

 'WeightLossFilterService' async service which checks if the is the word ‘cookie’


in it
 invoke that service inside .$doCheck and check if the items changed in the items
array if ($ctrl.items.length and if changed we check if there are cookies
 before we make the async call to 'WeightLossFilterService' , we are going to .
$broadcast an event using the $rootScope
 we .$broadcast the event using $rootScope because the component that
need to catch that is <loading-spinner></loading-spinner> which is not in
same path of the scope chain
 the .$broadcast event is 'shoppinglist:processing' and the data passed
is {on: true});
$rootScope.$broadcast('shoppinglist:processing', {on: true});
o this whole process shows to the user that we are processing
.finally(function () {
$rootScope.$broadcast('shoppinglist:processing', { on: false });
});
 .$broadcast the event when the spinner should turn off { on: false

SpinnerController.$inject = ['$rootScope']
function SpinnerController($rootScope) {
var $ctrl = this;

var cancelListener = $rootScope.$on('shoppinglist:processing', function


(event, data) {
console.log("Event: ", event); event listener shows
shoppingList:processing
console.log("Data: ", data); { on: false }; { on: true }

if (data.on) {
$ctrl.showSpinner = true;
}
else {
$ctrl.showSpinner = false;
}
});

$ctrl.$onDestroy = function () { triggers the distruction $rootScope.


$on
cancelListener();
};

};
 To listen for events use $scope.$on or $rootScope.$on

Modules
 Modules help us to split up our application into small part they then can be good together
angular.module( ‘module1’) or <html ng-
app=’module1’>
angular.module(‘module3, [ ‘module1’, ‘module2’] )
</html>
.controller(‘MyController’ , Mycontroller

<script src=”src/mod1/module1.js”>< /script>


angular.module(‘module1’)
<script src=”src/mode1/controller.js”></script> .config(function () {

<script src=src/mod2/module2.js”></script>
agular.module(‘module2’)
script src=”src/mode2/controller.js”></script> .run(function()
 [] – if you want to specify the 2 argument you create the module not retrieving
nd

an existing one
 It is best to separate js code into different files and best to place artifacts e.g
controllers into 1 file
 Doesn’t matter the order you declare your modules e.g start with module2 instead
of module1
 However you cannot declare an artifact before a module
 .config(function() - runs before any other methods in the module
o The function value passed into the config method, can be injected with a
provider or constants
 .run(function() – is executed right after the config method, can only inject
instances(e.g services) and constants not providers because we want to prevent
the system from being re-configured during run time
<!-- Libraries -->
<script src="lib/jquery-3.1.0.min.js"></script>
<script src="lib/angular.min.js"></script>

<!-- Modules -->

<script
src="src/shoppinglist/shoppinglist.module.js"></script>
<script src="src/spinner/spinner.module.js"></script>

<!-- 'ShoppingList' module artifacts -->


<script
src="src/shoppinglist/shoppinglist.component.js"></script>
<script
src="src/shoppinglist/shoppinglist.controller.js"></script>
<script
src="src/shoppinglist/shoppinglist.factory.js"></script>
<script
src="src/shoppinglist/weightlossfilter.service.js"></script>
<!-- 'Spinner' module artifacts -->
<script
src="src/spinner/loadingspinner.component.js"></script>

Routing
 2 types of package to use for routing implantation in a angularjs app
-ng-route
-ui-router
ngRoute Ui-router
- Separate Js file - Separate JS file
- Developed by google & - Developed by community
community - UI state is central( can have a
- No concept of UI state route with no unique URL for that
- Every route must be represented route)
by a URL - URL routing is also supported( UI
- No concept of nested views state is updated based on the URL
- OK for prototype projects - Nested view supported
- Better choice for more serious
projects

<script src=”lib/angular.min.js”></script>
angular.module(‘App’, [‘ui.router’]
<script src=lib/angular-ui-router.min.js”></script>

<body>
<ui-view></ui-view>

Angular.module(“app”)
.config(RoutesConfig)
RoutesConfig.$inject = [‘$stateProvider’ , ‘$urlRouterProvider’];
Function routersConfig(‘$stateProvider’ , ‘$urlRouterProvider’){}

$stateProvider.state(‘view1, { $urlRouterProvider.otherwise(‘/
url: view1’)
‘/view1’, $stateProvider.state(‘view1’, {
url:
template: <div></div} /view1}
.state(‘view2, {})

 Ui-router is referenced After the angular package(<script


src=”lib/angular.min.js”></ )
 Content of the view will be loaded here <ui-view></ui-view>
 Declare ui-router as a dependency
o The name of the module is .router not –router (‘App’, [‘ui.router’]
 Optional URL url: ‘/view1’ associated with the state
 Content of the template template: <div></div} will be inserted into <ui-
view>
 $urlRouterProvider.otherwise(‘/view1’) – tells the url router that when
you try to match a browser url with the url associated with a particular declared
state and it cant find any matches it could default to the url declared in the
.otherwise method
o Any url that the url router cant match will default to to the view1’,
{ url:.view1

angular.module('RoutingApp',['ui.router']);

angular.module('RoutingApp')
.config(RoutesConfig);

RoutesConfig.$inject = ['$stateProvider', '$urlRouterProvider'];


function RoutesConfig($stateProvider, $urlRouterProvider) {

// Redirect to tab 1 if no other URL matches


$urlRouterProvider.otherwise('/tab1'); //if there is no state it will
automatically jump to this webpage

// Set up UI states
$stateProvider
.state('tab1', {
url: '/tab1', //hyperlink
templateUrl: 'src/tab1.html'
})

.state('tab2', {
url: '/tab2',
templateUrl: 'src/tab2.html'
});
}

<div class="tabs">
<a ui-sref="tab1" ui-sref-active="activeTab">Tab 1</a>
<a ui-sref="tab2" ui-sref-active="activeTab">Tab 2</a>
<!-- <button ui-sref="tab2">Tab 2</button> -->
</div>
 ui-sref="tab1" – ui router state reference
 "tab1" === .state('tab1' must match/ must be equal
 If you were to comment out url: '/tab2' , tab2 will no longer be a hyper link but you can
still press tab2 to execute the information inside
 ui-sref-active="activeTab"> -let us specify a css class that should be applied to a
specific tag

Route state with controller

State config Declare controller in state configuration


.state( ‘home’ , { .state( ‘home’ , {
url: ‘/’ , url: ‘/’ ,
templateUrl: ‘home.html’ templateUrl: ‘home.html’
controller: ‘HomeCtrl as home’
<div ng-controller=’HomeCtrl as
home’> <div>content…</div>
<div>content…</div> <div>content…</div>
<div>content…</div>

- ’homeCtrl inefficient because this


tag is only here to declare controller

Routes.js
angular.module('ShoppingList')
.config(RoutesConfig);

RoutesConfig.$inject = ['$stateProvider', '$urlRouterProvider'];


function RoutesConfig($stateProvider, $urlRouterProvider) {

// Redirect to home page if no other URL matches


$urlRouterProvider.otherwise('/');

// *** Set up UI states ***


$stateProvider

// Home page
.state('home', {
url: '/',
templateUrl: 'src/shoppinglist/templates/home.template.html'
})
// Premade list page
.state('mainList', {
url: '/main-list',
templateUrl: 'src/shoppinglist/templates/main-
shoppinglist.template.html',
controller: 'MainShoppingListController as mainList'
});
 RoutesConfig Sets up a couple of states .state
 1st of all it re-routes anything that doesn’t match any particular url
$urlRouterProvider.otherwise('/' to a slash('/') or home page
.state('home', { and its template url is templateUrl:
'src/shoppinglist/templates/home.template.html' e which is a very
short template
Home.template.html
<a ui-sref="mainList">See our Premade No Cookie Shopping List!
</a>
o It is using state reference ui-sref= to "mainList"> so "mainList">
better be a state we defined in routes.js .state('mainList',
 The template url of .'mainList' which is templateUrl
'src/shoppinglist/templates/main-shoppinglist.template.html' is
pointing to
Main-shoppinglist.template.html
<div id="list" ng-controller='MainShoppingListController as
mainList'> declares a controller labelled mainList
<a ui-sref="home">Home</a> &lt; <span>List</span>
<h3>Premade List with Absolutely No Cookies in it</h3>
<shopping-list items="mainList.items"></shopping-list>
</div>
o <a ui-sref="home">Home</a> &lt; <span>List</span>
declaring a link that helps us go back to the home
screen
o it uses the shoppinglist component <shopping-list to
output the list
 Shoppinglist.component.js
angular.module('ShoppingList')
.component('shoppingList', {
templateUrl:
'src/shoppinglist/templates/shoppinglist.template.html',
bindings: {
items: '<'
}
o The shopping list component just passes along the items items: which is
the list of our shopping items and it is pointing us to a url templateUrl:
'src/shoppinglist/templates/shoppinglist.template.html'
 Shoppinglist.template.html
<li ng-repeat="item in $ctrl.items">
{{ item.quantity }} of {{ item.name }}
</li>
o Loop over the item quantity and name to output the list
{{ item.quantity }} of {{ item.name }}
Main-shoppinglist.controller
angular.module('ShoppingList')
.controller('MainShoppingListController', MainShoppingListController);

MainShoppingListController.$inject = ['ShoppingListService'];
function MainShoppingListController(ShoppingListService) {
var mainList = this;
mainList.items = [];

mainList.$onInit = function () {
ShoppingListService.getItems()
.then(function (result) {
mainList.items = result;
});
 Main-shoppinglist.controller - Its is outputting the whole list to begin with
 We injected the 'ShoppingListService'into it and we are using the
'ShoppingListService’ in order to initialize these mainList.items
o We use a promise .getItems()which is returning a promise since we
use the .then method and when only the promise returns we are setting
the mainList.items to the = result which its returning (result)
 Shoppinglist.service.js
ShoppingListService.$inject = ['$q', '$timeout']
function ShoppingListService($q, $timeout) {
var service = this;

// List of shopping items


var items = [];

// Pre-populate a no cookie list


items.push({
name: "Sugar",
quantity: "2 bags",
description: "Sugar used for baking delicious umm... baked
goods."
});
items.push({
name: "flour",
quantity: "1 bags",
description: "High quality wheat flour. Mix it with
water,sugar, 2 raw eggs."
});
items.push({
name: "Chocolate Chips",
quantity: "3 bags",
description: "Put these in the dough. No reason, really.
Gotta store them somewhere!"
});

// Simulates call to server


// Returns a promise, NOT items array directly
service.getItems = function () {
var deferred = $q.defer();

// Wait 2 seconds before returning


$timeout(function () {
// deferred.reject(items);
deferred.resolve(items); the items are delayed from
returning
}, 800);

return deferred.promise;
o We use a promise because we are simulating a call to a server
o That server call comes back to the main-shoppinglist.controller and the
mainList.items gets set , which then goes to main-
shoppinglist.template.html and able to pass
items="mainList.items"></ into shoppinglist component
<shopping-list then goes ahead to output the shopping list
Shoppinglist.template.html {{ item.quantity }} of {{ item.name
}}

Route state with resolve

.state( ‘view1’ , { View1Ctrl.$inject =


[myData]
url: ‘/view1’ , function
View1Ctrl(myData){
templateUrl: ‘view1.html’ let view1 = this;
controller: ‘View1Ctrl as view1’, view1.myData =
myData
resolve: {
myData: [‘Service’, function (Service){
return Service.getData()
}]

 resolve Is a configuration object that has some key and value pairs
o can be used to inject values directly into the controller responsible for the state
 Service.getData() return a promise
 myData is going to have a value, which is going to be injected into the view1
controller with the key of myData
o if the resolve property which is myData gets aside a promise, the router will
not advance us to the new state(‘view1’) until the promise is resolved, if the
promise is rejected all together the router will not advance us to the new state
 the name of the key in the resolve’s property object is what is to be injected into the
corresponding controller function
o resolve can have properties that can contain anything : object, string, etc
 when clicking the link on the webpage(main-list),the list pops in 800 millisecond late because we
are switching the view 1st and then get the data
 create a resolve property in the route

.state('mainList', {
url: '/main-list',
templateUrl: 'src/shoppinglist/templates/main-
shoppinglist.template.html',
controller: 'MainShoppingListController as mainList',
resolve: {
items: ['ShoppingListService', (ShoppingListService) => {
return ShoppingListService.getItems()

 items: property is going to resolve to a promise that gets returned by the


shoppingListService
 ShoppingListService.getItems() these will immediately return a promise and
url router will wait for the item property items to get resolved before it takes us to the
'mainList' url state

// MainShoppingListController.$inject = ['ShoppingListService'];
// function MainShoppingListController(ShoppingListService) {
MainShoppingListController.$inject = ['items'];
function MainShoppingListController(items) {
var mainList = this;
mainList.items = items
// mainList.$onInit = function () {
// ShoppingListService.getItems()
// .then(function (result) {
// mainList.items = result;
// });
// };
}

Route state with URL parameters


.state( ‘view1’ , { View1Ctrl.$inject =
[‘myData’]
url: ‘/view1’/{param1} , function
View1Ctrl(myData){
templateUrl: ‘view1.html’ let view1 = this;
controller: ‘View1Ctrl as view1’, view1.myData =
myData
resolve: {
myData: [‘$stateParams’, ‘ <a ui-
sref=”view1({itemId : someVal})”>
function ($stateParams){ Link to view with
data
return getDataBasedOn($stateParams.param1) </a>
}]

url: ‘/view1/{param1}’

 /view1/{param1} -> /view1/ -> /view1/hello or /view1/12


 State url properties can be declared with parameters
 Parameters are wrapped in braces /{paramName}
 Use $stateParams service to retrieve parameters e.g $stateParams.paramName
 We want to make the items clickable, so that when clicking name(item) they must have details
about the shoppingList item
 Construct a url with a ui-sref directive ui-sref=”stateName({paramName: value})”
 Specify the stateName as a function then pass an object function such that the keys in
the object are the parameter names declared in the state url property

.state('itemDetail', {
url: '/item-detail/{itemId}',
templateUrl: 'src/shoppinglist/templates/item-detail.template.html',
controller: 'ItemDetailController as itemdetail',
resolve: {
item: ['$stateParams', 'ShoppingListService',
($stateParams, ShoppingListService) => {
return ShoppingListService.getItems().then( (items) => {
return items[$stateParams.itemId] refers to the specific item
looked at
}
 {itemId} Tell us which item id (0 or 1 or 2) with 3 items since its an array it is 0 base
 '$stateParams'give use the value of this parameter itemId

angular.module('ShoppingList')
.controller('ItemDetailController', ItemDetailController);
//'item' is injected through state's resolve
ItemDetailController.$inject = ['item']protects the controller from
manification
function ItemDetailController(item){
let itemdetail = this;
itemdetail.name = item.name;
itemdetail.quantity = item.quantity;
itemdetail.description = item.description;
}
 itemdetail Instance of our controller ItemDetailController which we are using inside
of our template
<a ui-sref="home">Home</a> &lt;
<a ui-sref="mainList">List</a> &lt;

<span>{{ itemdetail.name }}</span> //these template


<div>Item name: {{ itemdetail.name}}</div>
<div>Item quantity: {{ itemdetail.quantity }}</div>
<div>Item description: {{ itemdetail.decription }}</div>

<li ng-repeat="item in $ctrl.items" ui-sref="itemDetail({itemId:


$index})">
{{ item.quantity }} of {{ item.name }}
</li>
</ul>

Route state with nested views

You might also like