Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ng-repeat with ng-transclude inside a directive

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
like image 338
Jan Avatar asked Jan 17 '13 21:01

Jan


People also ask

What is transclude in AngularJS directive?

The ng-transclude directive facilitates AngularJS to capture everything that is put inside the directive in the markup and use it somewhere in the directive's template.

Does ng-repeat create a new scope?

Directives that Create Scopes In most cases, directives and scopes interact but do not create new instances of scope. However, some directives, such as ng-controller and ng-repeat, create new child scopes and attach the child scope to the corresponding DOM element.

What does ng-repeat do?

Definition and Usage. The ng-repeat directive repeats a set of HTML, a given number of times. The set of HTML will be repeated once per item in a collection. The collection must be an array or an object. Note: Each instance of the repetition is given its own scope, which consist of the current item.

What is transclusion in Javascript?

transclude:true mean to add all element that is defined in your directive with template element of your directive. if transclude:false the these elements are not included in your final html of directive only template of directive is rendered.


1 Answers

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);       }             }   } }); 
like image 64
Jan Avatar answered Oct 04 '22 04:10

Jan