On Github cvuorinen / angularjs-internals-slides
by Carl Vuorinen / @cvuorinen
HTML enhanced for web apps!
<h4>Hello {{name}}!</h4>
<input ng-model="name">
<h4>Todo:</h4>
<ul ng-init="list=[];">
<li ng-repeat="todo in list"
ng-click="list.splice($index, 1)">
{{todo}}
</li>
</ul>
<form ng-submit="list.push(todo);todo='';">
<input ng-model="todo" placeholder="Add">
</form>
Plain Old Javascript Object
red border== "pseudo" code
$scope.$watch = function(watchFunc, listenerFunc) {
this.$$watchers.push({
watchFunc: watchFunc,
listenerFunc: listenerFunc
});
};
$scope.$digest = function() {
var dirty = true;
var scope = this;
while (dirty) {
dirty = false; // reset from last iteration
scope.$$watchers.map(function (watcher) {
// execute watch function to get new value
newValue = watcher.watchFunc(scope);
// check if value has changed from last cycle
if (newValue !== watcher.lastValue) {
dirty = true;
// execute listener and store new last value
watcher.listenerFunc(newValue, watcher.lastValue, scope);
watcher.lastValue = newValue;
}
});
}
};
function Vehicle() {}
Vehicle.prototype.speed = 4;
Vehicle.prototype.go = function() {
return 'Vr'
+ 'o'.repeat(this.speed)
+ 'm!';
};
function Truck() {}
Truck.prototype = Vehicle.prototype;
var scania = new Truck();
scania.go(); // Vroooom!
function Car(speed) {
this.speed = speed;
}
Car.prototype = Object.create(
Vehicle.prototype
);
Car.prototype.constructor = Car;
var honda = new Car(6);
honda.go(); // Vroooooom!
var tesla = new Car(12);
tesla.go(); // Vroooooooooooom!
$scope.$new = function() {
var ChildScope = function() {};
ChildScope.prototype = this;
return new ChildScope();
};
<label>
<input type="checkbox" ng-model="show">
Show me the Money!
</label><br>
<label ng-if="show">
<input type="checkbox" ng-model="showMore">
SHOW MOAR MONEY!!1
</label>
<div ng-if="show">
<img src="img/money.jpg"><br>
<img ng-if="showMore"
src="img/mo-money.jpg">
</div>
angular.module('app')
.controller("SomeController", function() {
this.value = "Hello!";
});
<div ng-controller="SomeController as some">
{{ some.value }}
</div>
angular.module('app')
.controller("SomeController", function() {
var vm = this;
vm.value = "Hello!";
vm.sayHello = function() {
alert(vm.value);
}
});
<div ng-controller="SomeController as vm">
<input type="text" ng-model="vm.value">
<button ng-click="vm.sayHello()">Click here</button>
</div>
<div ng-init="jsFrameworks = npm.search({tags: ['framework']})">
<div ng-if="(lastWeekCount = (jsFrameworks | since:lastWeek).length) > 10">
<h3>Holy smokes, Batman!</h3>
<p>New JS frameworks since last week: {{ lastWeekCount }}
<small>
+{{ (lastWeekCount / jsFrameworks.length * 100) | number:1 }}%
</small>
</p>
<p>Time to <button ng-click="startOver()">Clear the Decks!</button></p>
</div>
</div>
is kinda like
$parse = function(expr) {
return function(scope) {
with (scope) {
return eval(expr);
}
}
}
... except it's really not
angular.module('app')
.directive('awesomeButton', function() {
return {
scope: {
click: '&',
icon: '@'
},
transclude: true,
template: '<button class="button" '+
' ng-click="click()">'+
'<i class="fa fa-{{icon}}"></i>'+
'<span ng-transclude></span>'+
'</button>'
};
});
<div>
<awesome-button icon="bullhorn"
click="my.alert()">
Click here!
</awesome-button>
</div>
<div ng-init="arr=['Foo','Bar']">
<div ng-repeat="item in arr">
<button ng-click="submit(item)">
{{ item }}
</button>
</div>
</div>
<div>
<my-directive>
<p>Some Content</p>
</my-directive>
</div>
angular.module('app')
.directive('myDirective', function() {
return {
transclude: true,
template: '<div>' +
'<h4>Title</h4>' +
'<div ng-transclude></div>' +
'</div>'
};
});
angular.module('ng')
.directive('ngInit', function($parse) {
return {
link: function (scope, element, attrs) {
$parse(attrs.ngInit)(scope);
}
};
});
angular.module('ng')
.directive('ngClick', function($parse) {
return {
link: function (scope, element, attrs) {
var expression = $parse(attrs.ngClick);
element.on('click', function() {
scope.$apply(function () {
expression(scope);
});
});
}
};
});
angular.module('ng')
.directive('ngRepeat', function($parse, $transclude) {
return {
transclude: 'element',
link: function (scope, element, attrs) {
var match = attrs.ngRepeat.match(/^\s*([\s\S]+?) ... \s*$/);
$scope.$watch($parse(match.target), function (collection) {
// locate existing items, mark items not present for removal
// remove leftover items
// update existing items' scopes
// create new elements with $transclude
// and keep a reference to their scopes
});
}
};
});
angular.module('ng')
.directive('ngModel', function() {
return {
link: function (scope, element, attrs) {
var currentValue;
element.on('keyup', function() {
if ($(element).val() != currentValue) {
scope.$apply(function () {
scope[attrs.ngModel] = currentValue = $(element).val();
});
}
});
$scope.$watch(attrs.ngModel, function (newValue) {
currentValue = newValue;
$(element).val(newValue);
});
}
};
});
<!-- BAD -->
<label>The Ultimate Question</label>
<input ng-model="question">
Answer: {{ deepThought.compute(question) }}
<!-- LITTLE BETTER -->
<label>The Ultimate Question</label>
<input ng-model="question"
ng-change="answer = deepThought.compute(question)">
Answer: {{ answer }}
<!-- GOOD -->
<label>The Ultimate Question</label>
<input ng-model="question"
ng-change="answer = deepThought.compute(question)"
ng-model-options="{ debounce: 1000 }">
Answer: {{ answer }}
<h4>Todo:</h4>
<ul ng-init="list=[];">
<li ng-repeat="todo in list"
ng-click="list.splice($index, 1)">
{{todo}}
</li>
</ul>
<form ng-submit="list.push(todo);todo='';">
<input ng-model="todo" placeholder="Add">
</form>