Inline editing an expanding array with Angular
Mechanics behind a growing array of items that can be edited inline. See http://iweinfuld.posterous.com/expanding-collections-with-inline-edit-in-ang
by iweinfuld
HTML
<script src="http://code.angularjs.org/1.1.0/angular.min.js"></script>
<script src="http://underscorejs.org/underscore-min.js"></script>
<link rel="stylesheet" href="http://twitter.github.com/bootstrap/assets/css/bootstrap.css">
<div ng-app="app" class="container" ng-controller="Ctrl">
<div class="row">
<div class="span5 well" >
<div class="row" editable-collection="item in items" expanding-on="value">
<input type="text" ng-model="item.value" class="span2"/>
<p class="span2 pull-right">{{item.value}}</p>
</div>
</div>
</div>
<div class="row"><div class="span5 well">items:{{items|json}}</div></div>
<div class="row"><div class="span5 well">overflow:{{overflow|json}}</div></div>
</div>
JavaScript
var $scope;
var app = angular.module('app', []);
/**
* Creates an ng-repeat with an overflow area to enable inline editing with overflow.
*
* Nesting is not supported.
*/
app.directive('editableCollection', function factory($compile) {
return {
link: function (scope, el, attrs, controller) {
//parse the element and attributes
if (!attrs.expandingOn) {
throw 'Expected exanding-on attribute on element: '
+ el.html() + '\n but found: '
+ JSON.stringify(attrs.$attr) + '\n';
}
var split = attrs.editableCollection.split(' ');
var elementName = split[0];
var collectionName = split[2];
if (split.length != 3 || split[1] != 'in') {
throw 'Expected editable collection defined as "{element} in {collection}" got: '
+ attrs.editableCollection;
}
//Take the elements from this one to move to a child ng-repeat
var original = el.contents();
//Add the ng-repeat for the actual collection
var repeater = angular.element('<div/>');
repeater.attr('ng-repeat', attrs.editableCollection);
repeater.append(original);
el.append(repeater);
//Add the ng-repeat for the overflow
var overflowId = 'shouldBeUniquelyGeneratedToAvoidCollisions';
console.log('Created overflow with id: '+overflowId+ ' for '+collectionName);
scope[overflowId] = [
{}
];
var overflow = repeater.clone();
overflow.attr('ng-repeat',
attrs.editableCollection.replace(collectionName, overflowId));
el.append(overflow);
//Watch the first element and expand the overflow if needed
scope.$watch(overflowId+'[0].' + attrs.expandingOn, function (value) {
if (value &&...