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>