ng-repeat in combination with custom directive

19,323

Solution 1

Your directive needs to run before ng-repeat by using a higher priority, so when ng-repeat clones the element it is able to pick your modifications.

The section "Reasons behind the compile/link separation" from the Directives user guide have an explanation on how ng-repeat works.

The current ng-repeat priority is 1000, so anything higher than this should do it.

So your code would be:

angular.module('myApp', [])
    .directive('templateField', function () {
        return {
            restrict: 'E',
            priority: 1001, <-- PRIORITY
            compile: function(element, attrs, transcludeFn) {
                element.replaceWith('<input type="text" />');
            }
        };
});

Solution 2

Put your ng-repeat in the template. You could modify attributes of element and accordingly in directive to determine if ng-repeat is needed, or what data to use inside the directive compiling

HTML(attribute):

<div ng-app="myApp" template-field></div>

JS:

angular.module('myApp', [])
    .directive('templateField', function () {
        return {          
            restrict: 'A',
            template:'<input type="text" value="{{field}" ng-repeat="field in [\'title\',\'body\']" />'            
        };
    });

DEMO: http://jsfiddle.net/GDfxd/3/

Also works as an element :

HTML(element):

<div ng-app="myApp" >
    <template-field/>
</div>

JS

angular.module('myApp', [])
    .directive('templateField', function () {
        return {          
            restrict: 'E',
            replace:true,
            template:'<input type="text" value="{{field}}" ng-repeat="field in [\'title\',\'body\']" />'

        };
    });

DEMO: http://jsfiddle.net/GDfxd/3/

Share:
19,323

Related videos on Youtube

vrutberg
Author by

vrutberg

Updated on June 04, 2022

Comments

  • vrutberg
    vrutberg almost 2 years

    I'm having an issue with using the ng-repeat directive in combination with my own custom directive.

    HTML:

    <div ng-app="myApp">
      <x-template-field x-ng-repeat="field in ['title', 'body']" />
    </div>
    

    JS:

    angular.module('myApp', [])
        .directive('templateField', function () {
            return {
                restrict: 'E',
                compile: function(element, attrs, transcludeFn) {
                    element.replaceWith('<input type="text" />');
                }
            };
        });
    

    See jSFiddle

    The problem here is that nothing is replaced. What I'm trying to accomplish is an output of 2x input fields, with the 'x-template-field' tags completely replaced in the DOM. My suspicion is that since ng-repeat is modifying the DOM at the same time, this won't work.

    According to this Stack Overflow question, the accepted answer seems to indicate this has actually worked in earlier versions of AngularJS (?).

    Wouldn't element.html('...') work?

    While element.html('...') actually injects the generated HTML into the target element, I do not want the HTML as a child element of the template tag, but rather replace it completely in the DOM.

    Why don't I wrap my template tag with another tag that has the ng-repeat directive?

    Basically, for the same reason as above, I don't want my generated HTML as a child element to the repeating tag. While it would probably work decently in my application, I would still feel like I've adapted my markup to fit Angular and not the other way around.

    Why am I not using the 'template' property?

    I haven't found any way to alter the HTML retrieved from the 'template' / 'templateUrl' properties. The HTML I want to inject is not static, it's dynamically generated from external data.

    Am I too picky with my markup?

    Probably. :-)

    Any help is appreciated.

  • vrutberg
    vrutberg about 11 years
    It is difficult for me to use the 'template' property, because the HTML I want to generate for each field could be a lot of things. It could be an input tag, a textarea tag, or something completely different (such as markup triggering another directive). This is why I want to use the 'compile' property to specify a function that can insert virtually anything into the DOM.