ng-repeat works

This commit is contained in:
Misko Hevery 2010-03-22 15:46:34 -07:00
parent 84552f7f8a
commit b4561ff951
4 changed files with 77 additions and 18 deletions

View file

@ -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);

View file

@ -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)));
}
});

View file

@ -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
// <div ng-watch="$anchor.book: book=Book.get();"/>
angular.directive("watch", function(expression, element){
angularDirective("watch", function(expression, element){
var watches = {
'lhs':'rhs'
}; // parse

View file

@ -66,6 +66,20 @@ describe("directives", function(){
expect(element.text()).toEqual('brad;');
});
it('should ng-repeat over object', function(){});
it('should error on wrong parsing of ng-repeat', function(){});
it('should ng-repeat over object', function(){
var scope = compile('<ul><li ng-repeat="(key, value) in items" ng-bind="key + \':\' + value + \';\' "></li></ul>');
scope.set('items', {misko:'swe', shyam:'set'});
scope.updateView();
expect(element.text()).toEqual('misko:swe;shyam:set;');
});
it('should error on wrong parsing of ng-repeat', function(){
var scope = compile('<ul><li ng-repeat="i dont parse"></li></ul>');
var log = "";
element.eachNode(function(li){
log += li.attr('ng-error') + ';';
log += li.hasClass('ng-exception') + ';';
});
expect(log).toEqual("\"Expected ng-repeat in form of 'item in collection' but got 'i dont parse'.\";true;");
});
});