Intro into AngularJS
(and then some)
Before we begin
- Functions are first-class
- Control flow and hoisting
- Function-level scopes
- Closures
- Global scope
- Async
Functions are first-class
//Functions do not need to be wrapped by a class
function hello() {
console.log('Hello world');
}
hello();
//=>Hello worldFunctions are first-class
//Functions can return functions
function sayHello() {
return function() {
console.log('Hello world');
};
}
sayHello();
//=> [function]Functions are first-class
//Functions can be assigned to variables
var speak = sayHello();
speak();
//=>Hello world

Control Flow and hoisting
function sayHello() {
var name = 'Jack';
console.log('Hello ' + name);
}
sayHello();
//=> Hello JackControl Flow and hoisting
function sayHello() {
console.log('Hello' + name);
var name = 'Jack';
console.log('Hello' + name);
}
sayHello();//=> Hello undefined
//=> Hello Jack
function sayHello() {
var name;
console.log('Hello ' + name);
name = 'Jack';
console.log('Hello ' + name);
}
Control Flow and hoisting
function sayHello() {
var logToConsole = function() {
var name = 'Jack';
console.log('Hello ' + name);
}
logToConsole();
}
sayHello();
//=> Hello Jack
Control Flow and hoisting
function sayHello() {
logToConsole();
var logToConsole = function() {
var name = 'Jack';
console.log('Hello ' + name);
}
logToConsole();
}
sayHello();//=>TypeError: undefined is not a function
function sayHello() {
var logToConsole;
logToConsole();
logToConsole = function() {
console.log('Hello ' + name);
}
logToConsole();
}
Control Flow and hoisting
function sayHello() {
function logToConsole() {
var name = 'Jack';
console.log('Hello ' + name);
}
logToConsole();
}
sayHello();
//=> Hello JackControl Flow and hoisting
function sayHello() {
logToConsole();
function logToConsole() {
var name = 'Jack';
console.log('Hello ' + name);
}
logToConsole();
}
sayHello();//=> Hello Jack
//=> Hello Jack
function sayHello() {
function logToConsole() {
var name = 'Jack';
console.log('Hello ' + name);
}
logToConsole();
logToConsole();
}
Function-level scopes
function countTo(end) {
var numbers = [];
for(var i = 1; i <= end; i++) {
numbers.push(i);
}
console.log(numbers.join(','));
var i = 11;
console.log(i);
}
countTo(10);Javascript does not have block-level scoping; it has function-level scoping.
//=>1,2,3,4,5,6,7,8,9,10
//=>11
function countTo(end) {
var numbers;
var i;
numbers = [];
for(i = 1; i <= end; i++) {
numbers.push(i);
}
console.log(numbers.join(','));
i = 11;
console.log(i);
}Closures
function add(x) {
return function(y) {
return x + y;
}
}
var add1 = add(1);
add1(2);
//=>3Bonus: add1 is a partial application of add.

Global Scope
var name = 'Jack';
function sayHello() {
console.log('Hello ' + name);
}
sayHello();name and sayHello are now attached to the global object.

Global Scope
(function() {
var name = 'Jack';
function sayHello() {
console.log('Hello ' + name);
}
sayHello();
})();
sayHello();Immediately-Invoked Function Expression (IIFE)
//=>Hello Jack
//
//sayHello();
//^
//ReferenceError: sayHello is not defined
(function() { /* code */ }());
!function() { /* code */ }();
~function() { /* code */ }();
+function() { /* code */ }();
-function() { /* code */ }();Global Scope: Bonus
//We can use IIFEs and closures to emulate private properties and methods.
var car = (function() {
var make = 'Honda';
return {
logMake: logMake
};
function logMake() {
console.log(getMake());
}
function getMake() {
return 'The car\'s make is a ' + make + '.';
}
})();
car.logMake();
//=>The car's make is a Honda.
car.make = 'Tesla';
car.logMake();
//=>The car's make is a Honda.
console.log(car.make);
//=>Tesla
car.getMake();
//=>car.getMake();
// ^
//TypeError: Object #<Object> has no method 'getMake'

Async
var promises = {};
function getCases() {
var url = apiUrl + '/cases';
var key = 'get:' + url;
if (!promises[key]) {
promises[key] = $http
.get(url, httpConfig)
.then(onSuccess, onError, onDone);
}
return promises[key];
function onSuccess(success) {
return success;
}
function onError(error) {
errorStore.add(errorFactory.makeError('casesError', error.status));
}
function onDone() {
delete promises[key];
}
}Javascript is executed in single thread and the can be unresponsive during long tasks. Return a promise and continue execution when the task is complete.
Async
//lineGraph.js
function lineGraph() {
function init() {
getCases().then(calculate).then(render);
}
function calculate(data) {
return {
xAxis: data.map(byAxis('x')),
yAxis: data.map(byAxis('y')),
lines: data.map(ByLines)
};
}
function render(data) {
createLegend(data);
createXAxis(data);
createYAxis(data);
displayLines(data);
}
init();
}We can chain promises giving us a fluent interface
Async
//geoService.js
function factory($window, $q) {
var api = {
getGeoGps: getGeoGps
};
return api;
function getGeoGps() {
var options = {
maximumAge: 60000, timeout: 500, enableHighAccuracy: true
};
var deferred = $q.defer();
if (!$window.navigator || !$window.navigator.geolocation) {
deferred.reject();
} else {
// get latitude and longitude from HTML5 Geolocation
navigator.geolocation.getCurrentPosition(function onSuccess(position) {
deferred.resolve(position);
}, function onError(error) {
deferred.reject(error);
}, options);
}
return deferred.promise;
}
}Constructing a promise

A word of caution
this, prototype, call, apply, bind
MVW (Model View Whatever)
full-featured, opinionated framework
separation of concerns
designed to be testable
two-way binding
directives
Angular
Setup
-- root
|- App_Start
|- BundleConfig.cs
|-Views
|- Shared
|- _Layout.cstml
|- Scripts
|- Lib
|- angular.js
|- angular-ui-router.js
|- app
|- widget
|- configurations
|- state.cs
|- controllers
|- controller.js
|- directives
|- directive.js
|- services
|- service.js
|- views
|- view.html
|- app.jsSetup
// App_Start/BundleConfig.cs
public class BundleConfig
{
public static void RegisterBundles(BundleCollection bundles)
{
bundles.Add(new ScriptBundle("~/Content/js/widget").Include(
"~/Scripts/lib/angular.js",
"~/Scripts/lib/angular-ui-router.js",
"~/Scripts/app/widget/app.js",
"~/Scripts/app/widget/configurations/*.js",
"~/Scripts/app/widget/controllers/*.js",
"~/Scripts/app/widget/directives/*.js",
"~/Scripts/app/widget/services/*.js"
));
}
}Bootstrapping
<!-- Views/_Layout.cshtml -->
<!DOCTYPE html>
<head>
<title>Widgets!</title>
<link href="/~Content/app.css" rel="stylesheet">
</head>
<body>
<div data-ng-app="widget">
<div data-ui-view="content"></div>
</div>
@Scripts.Render("~/Content/js/widget");
</body>
</html>Modules
// Scripts/app/widget/app.js - module setter
!function(angular) {
angular
.module('widget', [
'ui.router'
]);
}(angular);// Scripts/app.widget/controllers/controller.js - module getter
!function(angular) {
angular
.module('widget')
.controller('myController', controller);
function controller() {
/* code */
}
}(angular);Dependency Injection
// Scripts/app/widget/configurations/config.js
!function(angular) {
angular
.module('widget')
.config(configuration);
configuration.$inject = ['$stateProvider', 'baseUrl'];
function configuration($stateProvider, baseUrl) {
/* code */
}
}(angular);Routing
// Scripts/app/widget/configurations/config.js
!function(angular) {
angular
.module('widget')
.config(configuration);
configuration.$inject = ['$stateProvider', '$urlRouterProvider', 'baseUrl'];
function configuration($stateProvider, $urlRouterProvider, baseUrl) {
$stateProvider
.state('index', {
url: '/',
views: {
'content': {
templateUrl: baseUrl + '/Scripts/app/widget/views/main.html',
controller: 'widget.mainController',
controllerAs: 'mainCtrl'
}
}
});
$urlRouterProvider
.otherwise('/');
}
}(angular);Controllers
// Scripts/app/widget/controllers/mainController.js
!function(angular) {
angular
.module('widget')
.controller('widget.mainController', controller);
controller.$inject = ['$scope', 'todoService'];
function controller($scope, todoService) {
var ctrl = this;
var api = {
data: {
list: null,
}
};
angular.extend(ctrl, api);
function init() {
todoService.getList().then(function(success) {
ctrl.data.list = success.data;
$scope.$broadcast('todo list loaded');
});
}
init();
}
}(angular);Two-way binding & Scopes
<!-- Scripts/app/widget/views/main.html -->
<ul data-ng-repeat="todo in mainCtrl.data.list | orderBy : 'dueOn'">
<li>
<input type="checkbox" data-ng-model="todo.isChecked">
{{todo.name}} - {{todo.dueOn}}
</li>
</ul>//watchers
$scope.$watch('property', function(newValue, oldValue) { /* code */ });
$scope.$watchGroup();
$scope.$watchCollection();
//Manually execute digest cycle for events outside of the framework
$scope.$apply();
//On destroy callback
$scope.$destroy(function() { /* code */ });
//event messaging
$scope.$emit('upstreamEvent', obj);
$scope.$broadcast('downstreamEvent', obj);
$scope.$on('upstreamEvent', function($event, obj) { /* code */ });
Directives
<!-- Scripts/app/widget/views/main.html -->
<ul data-ng-repeat="todo in mainCtrl.data.list | orderBy : 'dueOn'">
<li data-todo-item="todo"></li>
</ul><!-- Scripts/app/widget/directives/todo.html -->
<input type="checkbox" data-ng-model="todo.isChecked" data-ng-click="check()">
{{todo.name}} - {{todo.dueOn}}// Scripts/app/widget/directives/todo.js
!function (angular) {
angular
.module('widget')
.directive('todoItem', directive);
directive.$inject = ['todoService'];
function directive(todoService) {
var api = {
restrict: 'EA',
scope: {
todo: '&todoItem'
},
templateUrl: '/Scripts/app/widget/directives/todo.html',
link: link
};
return api;
function link(scope) {
scope.check = function() {
todoService.update(scope.todo.id, scope.todo);
};
}
}
}(angular);Directives
Services
!function (angular) {
angular
.module('widget')
.factory('todoService', factory);
factory.$inject = ['$http', 'baseUrl'];
function factory($http, baseUrl) {
var api = {
getList: getList,
get: get,
update update,
/* more methods */
};
return api;
function getList() {
return $http.get(baseUrl + '/todo').then(onSuccess, onError);
}
function update(id, todo) {
return $http.put(baseUrl + '/todo/' + id, todo).then(onSuccess, onError);
}
/* code */
}
}(angular);
Into the Future
ECMAScript 6
&
Angular 2.0
React
&
Flux
API Docs
https://docs.angularjs.org/api
Style Guide
https://github.com/johnpapa/angularjs-styleguide#modules
Newsletter
http://www.ng-newsletter.com/
Free Javascript Books
http://eloquentjavascript.net/
https://leanpub.com/javascript-allonge
http://addyosmani.com/resources/essentialjsdesignpatterns/book/
Copy of Introduction into Angular
By Praveen Poonia
Copy of Introduction into Angular
Introduction into Angular with a brief discussion on unique aspects of javascript.
- 901