【问题标题】:dynamically adding directives in ng-repeat在 ng-repeat 中动态添加指令
【发布时间】:2013-04-22 06:52:11
【问题描述】:

我正在尝试在 ng-repeat 中动态添加不同的指令,但是输出并未被解释为指令。

我在这里添加了一个简单的例子:http://plnkr.co/edit/6pREpoqvmcnJJWzhZZKq

控制器:

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

指令:

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>

如何使角度拾取通过 ng-repeat 输出的 class 中指定的指令?

【问题讨论】:

  • 有趣的问题!
  • 我不确定这是否可行。您可以将 color.name 作为参数传递给单个指令,然后检查值并从那里运行/调用适当的代码。

标签: angularjs angularjs-directive angularjs-ng-repeat


【解决方案1】:

我认为您不能只将指令指定为类名 - 您需要再次通过 $compile 运行它,这将导致递归错误。

一种可能的解决方案概述于:AngularJS - how to have a directive with a dynamic sub-directive

如果它适用于您的用例,您可以改用模板:

<div ng-repeat='template in inner' ng-include='template'></div>

【讨论】:

    【解决方案2】:

    我在我的一个项目中遇到了同样的问题,您可以在 jsfiddle 上查看我是如何解决这个问题的

    HTML:

    <div class="page-wrapper" ng-controller="mainCtrl">
      <div class="page">
        <h3>Page</h3>
        <ul>
            <li ng-repeat="widget in widgets"><div proxy="widget" proxy-value="{{widget}}"></div></li>
        </ul>
    </div>
    

    JS:

    var app = angular.module('app',[]);
    app.controller('mainCtrl', ['$scope', '$q', 'widgetAPI', function($scope, $q, widgetAPI) {
    $scope.widgets = [];
    widgetAPI.get().then(
        function(data) {
            $scope.widgets = data;
        },
        function(err) {
            console.log("error", err);
        }
    );}])
    
    .service('widgetAPI', ['$q', function($q) {
    var api = {};
    api.get = function() {
        //here will be $http in real app
        return $q.when(
            [
                {
                    component: 'wgtitle',
                    title: "Hello world",
                    color: '#DB1F1F',
                    backgroundColor: '#c1c1c1',
                    fontSize: '32px'
                },
                {
                    component: 'wgimage',
                    src: "http://cs425622.vk.me/v425622209/79c5/JgEUtAic8QA.jpg",
                    width: '100px'
                },
                 {
                    component: 'wgimage',
                    src: "http://cs425622.vk.me/v425622209/79cf/S5F71ZMh8d0.jpg",
                    width: '400px'
                }
    
            ]
        );
    };
    return api;}])
    
    .directive('proxy', ['$parse', '$injector', '$compile', function ($parse, $injector, $compile) {
    return {
        replace: true,
        link: function (scope, element, attrs) {
            var nameGetter = $parse(attrs.proxy);
            var name = nameGetter(scope);
            var value = undefined;
            if (attrs.proxyValue) {
              var valueGetter = $parse(attrs.proxyValue);
              value = valueGetter(scope);
            }
    
            var directive = $injector.get(name.component + 'Directive')[0];
            if (value !== undefined) {
                attrs[name.component] = value;
            }
            var a = $compile(directive.template)(scope);
            element.replaceWith(a);
        }
    }}])
    
    .directive('wgtitle', function() {
    return {
        restrict: 'A',
        scope: true,
        replace: true,
        template: '<h1 style="color:{{widget.color}}; font-size:{{widget.fontSize}}; background:{{widget.backgroundColor}}" >{{widget.title}}</h1>',
        link: function(scope, element, attrs) {
    
        }
    }})
    
    .directive('wgimage', function() {
    return {
        restrict: 'A',
        scope: true,
        replace: true,
        template: '<img style="width:{{widget.width}}" src="{{widget.src}}"/>',
        link: function(scope, element, attrs) {
    
        }
    }});
    

    希望对你有用。

    【讨论】:

    • 这是一种非常好的方法,可以避免 ng-repeat 中的 switch/if 根据某些标准选择不同的指令。在我看来,这是正确的答案。
    • 由于某种原因我无法弄清楚,动态插入指令的链接函数没有被调用。你能帮我找出原因和/或想一个解决方法吗?
    【解决方案3】:

    我知道这是一个老问题,但谷歌把我带到了这里,我不喜欢这里的答案......对于应该简单的事情来说,它们似乎真的很复杂。所以我创建了这个指令:

    ***** 新内容 *****

    我已经使这个指令更通用,支持解析(典型的角度值)“属性”属性。

    /**
     * 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);
                };
            }
        };
    });
    

    对于 OP 的用例,您可以这样做:

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

    或将其用作属性指令:

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

    ***** 结束新内容 ******

    /**
     * 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));
            }
        };
    })
    
    ;
    

    对于这个问题的具体情况,可以稍微重写指令,使其按类将指令应用于跨度,如下所示:

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

    然后您可以在任何地方使用它并通过名称动态选择指令。像这样使用它:

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

    我故意让这个指令简单明了。您可能(并且可能会)必须重新措辞以满足您的需求。

    【讨论】:

    • 完美!正是我的想法!
    • 远距离最佳答案。
    猜你喜欢
    • 1970-01-01
    • 2014-11-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-04
    相关资源
    最近更新 更多