Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
680 views
in Technique[技术] by (71.8m points)

angularjs - dynamically adding directives in ng-repeat

I am trying to dynamically add different directives in an ng-repeat however the output is not being interpreted as directives.

I've added a simple example here: http://plnkr.co/edit/6pREpoqvmcnJJWzhZZKq

Controller:

$scope.colors = [{name:"red"}, {name: "blue"}, {name:"yellow"}]; 

Directive:

app.directive("red", function () {
    return {
        restrict: 'C',
        template: "RED directive"
    }
});

Html:

<ul>
  <li ng-repeat="color in colors">
    <span class="{{color.name}}"></span>
  </li>
</ul>

How do I make angular pick up the directive specified in the class that is output via ng-repeat?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I know this is an old question, but google brought me here, and I didn't like the answers here... They seemed really complicated for something that should be simple. So I created this directive:

***** NEW CONTENT *****

I've since made this directive more generic, supporting a parsed (the typical angular value) "attributes" attribute.

/**
 * Author: Eric Ferreira <http://stackoverflow.com/users/2954747/eric-ferreira> ?2016
 *
 * This directive takes an attribute object or string and adds it to the element
 *   before compilation is done. It doesn't remove any attributes, so all
 *   pre-added attributes will remain.
 *
 * @param {Object<String, String>?} attributes - object of attributes and values
 */
.directive('attributes', function attributesDirective($compile, $parse) {
    'use strict';

    return {
        priority: 999,
        terminal: true,
        restrict: 'A',
        compile: function attributesCompile() {
            return function attributesLink($scope, element, attributes) {
                function parseAttr(key, value) {
                    function convertToDashes(match) {
                        return match[0] + '-' + match[1].toLowerCase();
                    }

                    attributes.$set(key.replace(/([a-z][A-Z])/g, convertToDashes), value !== undefined && value !== null ? value : '');
                }

                var passedAttributes = $parse(attributes.attributes)($scope);

                if (passedAttributes !== null && passedAttributes !== undefined) {
                    if (typeof passedAttributes === 'object') {
                        for (var subkey in passedAttributes) {
                            parseAttr(subkey, passedAttributes[subkey]);
                        }
                    } else if (typeof passedAttributes === 'string') {
                        parseAttr(passedAttributes, null);
                    }
                }

                $compile(element, null, 999)($scope);
            };
        }
    };
});

For the OP's use case, you could do:

<li ng-repeat="color in colors">
    <span attributes="{'class': color.name}"></span>
</li>

Or to use it as an attribute directive:

<li ng-repeat="color in colors">
    <span attributes="color.name"></span>
</li>

***** END NEW CONTENT ******

/**
 * Author: Eric Ferreira <http://stackoverflow.com/users/2954747/eric-ferreira> ?2015
 *
 * This directive will simply take a string directive name and do a simple compilation.
 * For anything more complex, more work is needed.
 */
angular.module('attributes', [])

.directive('directive', function($compile, $interpolate) {
    return {
        template: '',
        link: function($scope, element, attributes) {
            element.append($compile('<div ' + attributes.directive + '></div>')($scope));
        }
    };
})

;

For the specific case in this question, one can just rewrite the directive a bit to make it apply the directive to a span by class, as so:

angular.module('attributes', [])

.directive('directive', function($compile, $interpolate) {
    return {
        template: '',
        link: function($scope, element, attributes) {
            element.replaceWith($compile('<span class="' + attributes.directive + '"></span>')($scope));
        }
    };
})

;

Then you can use this anywhere and select a directive by name dynamically. Use it like so:

<li ng-repeat="color in colors">
    <span directive="{{color.name}}"></span>
</li>

I purposely kept this directive simple and straightforward. You may (and probably will) have to reword it to fit your needs.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...