I want to create a list with custom behavior when it’s content changes. I try to create a directive for this but I get a bit lost with how to combine the ng-transclude with the ng-repeat directive. Can somebody put me on track?
Html:
<div ng-app="myApp"> <div ng-controller="ctrl"> <mylist items="myItem in items"> <span class="etc">{{myItem}}</span> </mylist> </div> </div>
Javascript:
angular.module('myApp', []) .controller('ctrl', function ($scope) { $scope.items = ['one', 'two', 'three']; }) .directive('mylist', function () { return { restrict:'E', transclude: 'element', replace: true, scope: true, template: [ '<ul>', '<li ng-repeat="WhatGoesHere in items" ng-transclude></li>', '</ul>' ].join(''), link: function (scope, element, attr) { var parts = attr.items.split(' in '); var itemPart = parts[0]; var itemsPart = parts[1]; scope.$watch(itemsPart, function (value) { scope.items = value; }); } } });
I’ve got part of this somewhat working here
EDIT:
Criteria:
- The template of the item must be defined in the view, not in the directive and it must have access to an item property in a child scope. Ideally I want to define this like it is done in the ng-repeat directive
- The directive must have access to the list so I can set proper watches and change things. If possible I would like to have easy access to the generated DOM items (I can also do it with
element[0].querySelectorAll('ul>li')
or something, It only has to work on Chrome). - If possible I would like to reuse the logic in the ng-repeat directive because it does already do a lot of what I want. Preferably I don’t want to copy the code. I just want to augment its behavior, not change it
Advertisement
Answer
Solved the problem myself:
I am able to do it in the compile step (jsfiddle) by adding the ng-repeat
attribute when the template is compiled and feeding it the content of my attribute.
Html:
<div ng-app="myApp"> <div ng-controller="ctrl"> <mylist element="myItem in items">{{myItem}}</mylist> </div> </div>
Javascript:
var myApp = angular.module('myApp', []) .controller('ctrl', function ($scope) { $scope.items = ['one', 'two', 'three']; }) .directive('mylist', function ($parse) { return { restrict:'E', transclude: 'element', replace: true, scope: true, template: [ '<ul>', '<li ng-transclude></li>', '</ul>' ].join(''), compile: function (tElement, tAttrs, transclude) { var rpt = document.createAttribute('ng-repeat'); rpt.nodeValue = tAttrs.element; tElement[0].children[0].attributes.setNamedItem(rpt); return function (scope, element, attr) { var rhs = attr.element.split(' in ')[1]; scope.items = $parse(rhs)(scope); console.log(scope.items); } } } });