Skip to content

Instantly share code, notes, and snippets.

@mhevery
Created January 31, 2011 18:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mhevery/804542 to your computer and use it in GitHub Desktop.
Save mhevery/804542 to your computer and use it in GitHub Desktop.
<!doctype html>
<html xmlns:ng="http://angularjs.org">
<script type="text/javascript" ng:autobind src="http://code.angularjs.org/0.9.10/angular-0.9.10.js"></script>
<script>
function MyApp(){
this.columns = ['name', 'description', 'amount'];
this.rows = [
{name:'name 0', description:'desc 0', amount:123},
{name:'name 1', description:'desc 1', amount:123},
{name:'name 2', description:'desc 2', amount:123},
{name:'name 3', description:'desc 3', amount:123},
{name:'name 4', description:'desc 4', amount:123},
{name:'name 5', description:'desc 5', amount:123},
{name:'name 6', description:'desc 6', amount:123},
{name:'name 7', description:'desc 7', amount:123},
{name:'name 8', description:'desc 8', amount:123},
{name:'name 9', description:'desc 9', amount:123},
];
}
angular.widget('xng:compile', function(element){
if (element.attr('compiled')) {
this.descend(true);
this.directives(true);
return;
}
var dataProp = element.attr('data');
// we romeve the template from the normal compile flow.
// this is because we can't unrole it just yet as we don't
// have the scope.
var templateHTML = element.html();
element.html('');
element.attr('compiled', true);
var compiler = this;
return function(element){
var scope = this;
this.$watch(this.$bind(this.$get, dataProp), function(){
// if the metadate changes then we have to precompile the template
var template = angular.element('<div>');
template.html(templateHTML);
var templateScope = angular.compile(template);
// copy the data which is neede for template eval into new scope
templateScope.$set(dataProp, scope.$get(dataProp));
templateScope.$init();
// now extract the compiled template and clean it up
cleanUpTemplate(templateScope.$element);
// insert the compiled template back to tree and recompile it.
element.html(templateScope.$element.html());
compiler.compile(element)(element, scope);
scope.$init();
});
}
function cleanUpTemplate(element){
var attributes = element[0].attributes || [];
var addBack = {};
var match;
for(var i = 0; i < attributes.length;) {
var attr = attributes[i];
if (match = attr.name.match(/^post-compile-(.+:.*)/)) {
// rename all attributes starting with 'post-compile...'
addBack[match[1]] = attr.value;
element.removeAttr(attr.name);
} else if (attr.name.match(/^.+:/)) {
// remove all existing bindings
element.removeAttr(attr.name);
} else {
i++;
}
}
element.attr(addBack);
// Reset the flags
element.removeClass('ng-directive');
element.removeClass('ng-binding');
element.removeClass('ng-attr-widget');
element.removeClass('ng-widget');
angular.forEach(element.children(), function(child){
if (element.nodeName == '#text') return;
cleanUpTemplate(angular.element(child));
});
}
});
</script>
<body ng:controller="MyApp">
<xng:compile data='columns'>
<table>
<thead>
<tr>
<td ng:repeat="column in columns">{{column}}</td>
</tr>
</thead>
<tr post-compile-ng:repeat="row in rows">
<td ng:repeat="prop in columns" post-compile-ng:bind="row.{{prop}}"></td>
</tr>
</table>
</xng:compile>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment