2013-04-28 14 views
19

Tôi đang cố gắng tự động thêm các chỉ thị khác nhau trong một ng-lặp lại tuy nhiên đầu ra không được hiểu là chỉ thị.tự động thêm chỉ thị trong ng-repeat

Tôi đã thêm một ví dụ đơn giản ở đây: http://plnkr.co/edit/6pREpoqvmcnJJWzhZZKq

Bộ điều khiển:

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

Chỉ thị:

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> 

Làm thế nào để thực hiện một gular nhận các chỉ thị quy định tại class đó là đầu ra thông qua ng-lặp lại?

+0

câu hỏi thú vị! – TheHippo

+0

Tôi không chắc chắn điều đó là có thể. Tuy nhiên, bạn có thể chuyển color.name thành tham số cho một chỉ thị duy nhất, sau đó kiểm tra giá trị và chạy/gọi mã thích hợp từ đó. – mikel

Trả lời

13

Tôi biết đây là một câu hỏi cũ, nhưng google đã đưa tôi đến đây và tôi không thích câu trả lời ở đây ... Chúng dường như thực sự phức tạp đối với một thứ đơn giản. Vì vậy, tôi đã tạo ra chỉ thị này:

***** NỘI DUNG MỚI *****

Tôi đã kể từ khi làm chỉ thị này chung chung hơn, hỗ trợ một phân tích cú pháp (giá trị góc điển hình) "thuộc tính" thuộc tính.

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

Đối với trường hợp sử dụng của OP, bạn có thể làm:

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

Hoặc sử dụng nó như một chỉ thị thuộc tính:

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

***** END NỘI DUNG MỚI ** ****

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

; 

Đối với trường hợp cụ thể trong q này Question, người ta chỉ có thể viết lại các chỉ thị một chút để làm cho nó áp dụng các chỉ thị để một khoảng bằng lớp, như vậy:

angular.module('attributes', []) 

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

; 

Sau đó, bạn có thể sử dụng bất cứ nơi nào này và chọn một chỉ thị theo tên động. Sử dụng nó như vậy:

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

Tôi cố tình giữ chỉ thị này đơn giản và dễ hiểu. Bạn có thể (và có lẽ sẽ) phải reword nó để phù hợp với nhu cầu của bạn.

+1

Hoàn hảo! Chỉ là những gì tôi đã nghĩ đến! – ironic

+1

Câu trả lời hay nhất bằng một cú sút dài. – Brian

3

Tôi không nghĩ bạn có thể chỉ định chỉ thị làm tên lớp - bạn sẽ cần phải chạy lại thông qua $compile, điều này sẽ hướng xuống đường dẫn tới lỗi đệ quy.

Một giải pháp khả thi được phác thảo tại địa chỉ: AngularJS - how to have a directive with a dynamic sub-directive

Nếu nó hoạt động đối với trường hợp sử dụng, bạn có thể sử dụng các mẫu thay vì:

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

tôi phải đối mặt với cùng một vấn đề thuộc một trong các dự án của tôi và bạn có thể thấy làm thế nào tôi giải quyết vấn đề này trên 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) { 

    } 
}}); 

Tôi hy vọng nó sẽ hữu ích.

+0

Đây là một cách cực kỳ tốt để tránh chuyển đổi/nếu trong một ng-lặp lại để chọn các chỉ thị khác nhau dựa trên một số tiêu chí. Theo tôi, đây là câu trả lời đúng. –

+0

Vì một số lý do tôi không thể tìm ra, chức năng liên kết của các chỉ thị được chèn động không được gọi. Bạn có thể giúp tôi tìm ra lý do và/hoặc nghĩ đến cách giải quyết không? – dvdplm

+0

JS fiddle ngã ba với các cảnh báo mà không bao giờ được gọi là: http://jsfiddle.net/rvss3oe1/ – dvdplm

Các vấn đề liên quan