From b4561ff951ff452e55e820f6f8344dc2668cfd90 Mon Sep 17 00:00:00 2001 From: Misko Hevery Date: Mon, 22 Mar 2010 15:46:34 -0700 Subject: ng-repeat works --- src/Angular.js | 25 +++++++++++++++++++++---- src/Compiler.js | 16 +++++++++++++++- src/directives.js | 36 +++++++++++++++++++++++++----------- 3 files changed, 61 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/Angular.js b/src/Angular.js index cfffab04..1549e7a7 100644 --- a/src/Angular.js +++ b/src/Angular.js @@ -181,15 +181,32 @@ function escapeAttr(html) { function bind(_this, _function) { var curryArgs = slice.call(arguments, 2, arguments.length); - if (!_this) - throw "Missing this"; - if (!_.isFunction(_function)) - throw "Missing function"; return function() { return _function.apply(_this, curryArgs.concat(slice.call(arguments, 0, arguments.length))); }; } +function bindTry(_this, _function) { + var args = arguments, + last = args.length - 1, + curryArgs = slice.call(args, 2, last), + exceptionHandler = args[last]; + return function() { + try { + return _function.apply(_this, curryArgs.concat(slice.call(arguments, 0, arguments.length))); + } catch (e) { + if (e = exceptionHandler(e)) throw e; + } + }; +} + +function errorHandlerFor(element) { + return function(error){ + element.attr('ng-error', angular.toJson(error)); + element.addClass('ng-exception'); + }; +} + function outerHTML(node) { var temp = document.createElement('div'); temp.appendChild(node); diff --git a/src/Compiler.js b/src/Compiler.js index 5c650204..ece44805 100644 --- a/src/Compiler.js +++ b/src/Compiler.js @@ -107,6 +107,20 @@ JQLite.prototype = { this.element.parentNode.insertBefore(jqLite(element).element, this.element.nextSibling); }, + hasClass: function(selector) { + var className = " " + selector + " "; + if ( (" " + this.element.className + " ").replace(/[\n\t]/g, " ").indexOf( className ) > -1 ) { + return true; + } + return false; + }, + + addClass: function( selector ) { + if (!this.hasClass(selector)) { + this.element.className += ' ' + selector; + } + }, + attr: function(name, value){ var e = this.element; if (isObject(name)) { @@ -201,7 +215,7 @@ Compiler.prototype = { exclusive = true; directiveQueue = []; } - directiveQueue.push(bind(selfApi, directive, value, element)); + directiveQueue.push(bindTry(selfApi, directive, value, element, errorHandlerFor(element))); } }); diff --git a/src/directives.js b/src/directives.js index 66a5e864..8047cdbd 100644 --- a/src/directives.js +++ b/src/directives.js @@ -10,7 +10,7 @@ angularDirective("ng-eval", function(expression){ }; }); -angular.directive("ng-bind", function(expression){ +angularDirective("ng-bind", function(expression){ return function(element) { this.$watch(expression, function(value){ element.text(value); @@ -18,23 +18,36 @@ angular.directive("ng-bind", function(expression){ }; }); -angular.directive("ng-bind-attr", function(expression){ +angularDirective("ng-bind-attr", function(expression){ return function(element){ this.$watch(expression, bind(element, element.attr)); }; }); -angular.directive("ng-non-bindable", function(){ +angularDirective("ng-non-bindable", function(){ this.descend(false); }); -angular.directive("ng-repeat", function(expression, element){ +angularDirective("ng-repeat", function(expression, element){ var reference = this.reference("ng-repeat: " + expression), r = element.removeAttr('ng-repeat'), template = this.compile(element), - path = expression.split(' in '), - lhs = path[0], - rhs = path[1]; + match = expression.match(/^\s*(.+)\s+in\s+(.*)\s*$/), + lhs, rhs, valueIdent, keyIdent; + if (! match) { + throw "Expected ng-repeat in form of 'item in collection' but got '" + + expression + "'."; + } + lhs = match[1]; + rhs = match[2]; + match = lhs.match(/^([\$\w]+)|\(([\$\w]+)\s*,\s*([\$\w]+)\)$/); + if (!match) { + throw "'item' in 'item in collection' should be identifier or (key, value) but got '" + + keyValue + "'."; + } + valueIdent = match[3] || match[1]; + keyIdent = match[2]; + var parent = element.parent(); element.replaceWith(reference); return function(){ @@ -42,7 +55,7 @@ angular.directive("ng-repeat", function(expression, element){ currentScope = this; this.$addEval(rhs, function(items){ var index = 0, childCount = children.length, childScope, lastElement = reference; - foreach(items, function(value, key){ + foreach(items || [], function(value, key){ if (index < childCount) { // reuse existing child childScope = children[index]; @@ -55,7 +68,8 @@ angular.directive("ng-repeat", function(expression, element){ lastElement.after(childScope.element); children.push(childScope); } - childScope.scope.set(lhs, value); + childScope.scope.set(valueIdent, value); + if (keyIdent) childScope.scope.set(keyIdent, key); childScope.scope.updateView(); lastElement = childScope.element; index ++; @@ -86,7 +100,7 @@ angular.directive("ng-repeat", function(expression, element){ //ng-show, ng-hide -angular.directive("action", function(expression, element){ +angularDirective("action", function(expression, element){ return function(){ var self = this; jQuery(element).click(function(){ @@ -97,7 +111,7 @@ angular.directive("action", function(expression, element){ //ng-watch //
-angular.directive("watch", function(expression, element){ +angularDirective("watch", function(expression, element){ var watches = { 'lhs':'rhs' }; // parse -- cgit v1.2.3