2013-04-28 127 views
19

動態地添加指令我試圖在NG-重複但輸出不被解釋爲指令動態添加不同的指令。在NG-重複

我這裏補充一個簡單的例子: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> 

如何使一個gular選取通過ng-repeat輸出的class中指定的指令?

+0

有趣的問題! – TheHippo 2013-04-28 18:33:37

+0

我不確定這是可能的。您可以將color.name作爲參數傳遞給單個指令,然後檢查該值並從那裏運行/調用相應的代碼。 – mikel 2013-04-28 20:54:44

回答

13

我知道這是一個老問題,但谷歌把我帶到這裏,我不喜歡這裏的答案......他們似乎的東西,應該是簡單非常複雜。所以我創造了這個指令:

*****新內容*****

因爲我已經使這個指令更通用,支持解析(典型的角度值)「屬性」屬性。

/** 
* 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> 

***** END新內容** ****

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

; 

對於q中的具體情況題目了,一個可以只改寫指令一下,以便它通過類的指令適用於跨度,像這樣:

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> 

我故意保持這個指令簡單明瞭。您可能(也可能會)必須對其進行修改以適應您的需求。

+1

完美!正是我想到的! – ironic 2016-01-10 16:44:59

+1

最佳答案通過一個遠投。 – Brian 2016-02-10 20:00:32

3

我不認爲你能夠將指令作爲類名分配 - 你需要再次運行$compile,這將會走向遞歸錯誤的路徑。

一個可能的解決方案在概述:AngularJS - how to have a directive with a dynamic sub-directive

它是否適合你的使用情況,您可以使用模板來代替:

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

我面臨着同樣的問題,在我的項目,你的一個可以看到我是如何上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) { 

    } 
}}); 

我希望這將有用。

+0

這是一個非常好的避免開關/如果在ng-repeat中根據某些標準選擇不同指令的好方法。在我看來,這是正確的答案。 – 2014-10-09 18:02:55

+0

出於某種原因,我不明白,動態插入的指令的鏈接功能不會被調用。你能幫我弄清楚爲什麼和/或想一個解決方法嗎? – dvdplm 2014-11-14 17:13:08

+0

JS小提琴與從不叫的警報:http://jsfiddle.net/rvss3oe1/ – dvdplm 2014-11-14 17:50:21