ngRepeat 对自定义指令标签

Posted

技术标签:

【中文标题】ngRepeat 对自定义指令标签【英文标题】:ngRepeat on custom directive tags 【发布时间】:2017-08-12 23:02:30 【问题描述】:

我的仪表板上有一个自定义指令列表,它们是不同的小部件。指令定义如下:

angular.module('core').directive('graphCardWidget', function() 
    return 
        restrict: 'E',
        replace: true,
        scope: 
            target: '=target'
        ,
        templateUrl: 'modules/core/widgets/graph-card.client.widget.html'
    ;
);

angular.module('core').directive('pieChartWidget', function() 
    return 
        restrict: 'E',
        replace: true,
        scope: 
            target: '=target'
        ,
        templateUrl: 'modules/core/widgets/pie-chart.client.widget.html'
    ;
);

在我的控制器中,我有一个要显示的小部件列表。名单如下:

$scope.dashboardWidgets = [
        
            directive : 'graph-card-widget',
            target : 'widgets.dashboards.activeDevicesCard'
        ,
        
            directive : 'graph-card-widget',
            target : 'widgets.dashboards.activeSessionsCard'
        ,
        
            directive : 'pie-chart-widget',
            target : 'widgets.dashboards.devices'
        ,
        
            directive : 'pie-chart-widget',
            target : 'widgets.dashboards.sessions'
        
    ];

现在在我看来,我使用ng-repeat 来迭代这个数组并显示项目。这是我的观点的代码:

<div layout="row" layout-wrap layout-align="center" layout-xs="column" ng-drop="true">
    <div ng-repeat='widget in dashboardWidgets'>
        <widget.directive ng-drag="true" flex='45' target='widget.target'>
        </widget.directive>
        <span flex='5'></span>
    </div>
</div>

但浏览器会将其呈现为文本。这是我在 DOM 中得到的内容:

<div layout="row" layout-wrap="" layout-align="center" layout-xs="column" ng-drop="true" class="layout-wrap layout-xs-column layout-align-center-stretch layout-row">
    <div ng-repeat="widget in dashboardWidgets" class="ng-binding ng-scope">
        “<graph-card-widget ng-drag="true" flex='45' target='widgets.dashboards.activeDevicesCard’>”
        <span flex="5" class="flex-5"></span>
    </div>
    <div ng-repeat="widget in dashboardWidgets" class="ng-binding ng-scope">
        “<graph-card-widget ng-drag="true" flex='45' target='widgets.dashboards.activeSessionsCard’>”
        <span flex="5" class="flex-5"></span>
    </div>
    <div ng-repeat="widget in dashboardWidgets" class="ng-binding ng-scope">
        “<pie-chart-widget ng-drag="true" flex='45' target='widgets.dashboards.devices’>”
        <span flex="5" class="flex-5"></span>
    </div>
    <div ng-repeat="widget in dashboardWidgets" class="ng-binding ng-scope">
        “<pie-chart-widget ng-drag="true" flex='45' target='widgets.dashboards.sessions’>”
        <span flex="5" class="flex-5"></span>
    </div>
</div>

那么我该怎么做才能使指令呈现为标签而不是纯文本?

我看到了一些类似的问题,例如question 1、question 2,但它们都在标准 HTML 标记中添加了动态指令。我需要的是动态标签。

更新:

按照@cnexans 的回答后,我得到了部分工作。已绘制小部件,但未评估 target 属性,这会导致出现空白小部件。 这是问题所在:https://plnkr.co/edit/BGN6C4LAHguWthU4fGy0?p=preview

【问题讨论】:

dynamically adding directives in ng-repeat的可能重复 看看这个 - 可能是重复的:***.com/questions/23130430/… 【参考方案1】:

您可以在 ng-for 中使用 ng-if,以便在每次迭代中切换名称“指令”以显示一个或另一个指令。

<div ng-repeat="data in dashboardWidgets">
    <div ng-if="data.directive == 'graph-card-widget'">
        <graph-card-widget ng-drag="true" flex='45' target=data.target>
        </graph-card-widget>
        <span flex='5'></span>
    </div>
    <div ng-if="data.directive == 'pie-chart-widget'">
        <pie-chart-widget ng-drag="true" flex='45' target=data.target>
        </pie-chart-widget>
        <span flex='5'></span>
    </div>
</div>

您也可以创建一个容器指令来处理此逻辑,因此您可以在需要时将此功能共享给其他页面。

<widgets-container widgets-list=data></widgets-container>

工作示例:https://codepen.io/anon/pen/jBzEpe?editors=1010#0

编辑:

检查您提供的示例,您需要将一个 Widget 对象传递给指令,并且您正在传递一个字符串。这是一个从给定的 plunkr 分叉的工作示例

https://plnkr.co/edit/3Oxxmp?p=preview

它有一个函数 namespaceToObject 将字符串从 $scope 转换为所需的对象。

【讨论】:

这种方法失败并出现错误Error: [$parse:syntax] Syntax Error: Token '' invalid key at column 2 of the expression [data.target] starting at [data.target]. 如果我删除data.target 周围的 ,它不会呈现小部件布局。 @Prera​​k Sola 抱歉,答案中添加了一个工作示例 我不知道为什么,但它仍然对我不起作用。 target 属性始终被评估为 data.target 而不是数组中的值。这是有问题的plunkr:plnkr.co/edit/BGN6C4LAHguWthU4fGy0?p=preview前两个是没有使用ng-repeat的小部件,接下来的两个是使用ng-repeat生成的。 这是因为你正在传递一个字符串,并且你想从 $scope 传递一个对象。尝试将字符串转换为所需的对象 *用工作 plunkr 编辑答案 是的,现在可以了。非常感谢您的帮助:)【参考方案2】:

不知道这是否符合您的要求。但我对你的数组做了一些修改。

我使用ng-bind-html 完成了此操作,当您绑定自定义元素(如指令)时,您需要再次编译它。为此我创建(实际上是借用)这个指令。

.directive('compileTemplate', function($compile, $parse)
    return 
        link: function(scope, element, attr)
            var parsed = $parse(attr.ngBindHtml);
            function getStringValue()  return (parsed(scope) || '').toString(); 

            //Recompile if the template changes
            scope.$watch(getStringValue, function() 
                $compile(element, null, -9999)(scope);  //The -9999 makes it skip directives so that we do not recompile ourselves
            );
                 
    
);

我把ng-repeat改成了这样

 <div ng-repeat='widget in dashboardWidgets' compile-template ng-bind-html="trust(widget.directive)">

        <span flex='5'></span>
 </div>

trust 函数将返回受信任的 html

 $scope.trust = function(someHTML) 
        return $sce.trustAsHtml(someHTML); 
 

像这样修改数组

$scope.dashboardWidgets = [
    
        directive : '<graph-card-widget ng-drag="true" flex="45" target="widget.target"></ graph-card-widget>',
        target : 'widgets.dashboards.activeDevicesCard'
    ,
    
        directive : '<graph-card-widget ng-drag="true" flex="45" target="widget.target"></ graph-card-widget>',
        target : 'widgets.dashboards.activeSessionsCard'
    ,
    
        directive : '<pie-chart-widget ng-drag="true" flex="45" target="widget.target"></ pie-chart-widget>',
        target : 'widgets.dashboards.devices'
    ,
    
        directive : '<pie-chart-widget ng-drag="true" flex="45" target="widget.target"></ pie-chart-widget>',
        target : 'widgets.dashboards.sessions'
    
];

Demo

【讨论】:

我尝试将它与我的应用程序集成,但它不起作用。它从字面上打印指令值。这是问题所在:plnkr.co/edit/UNzMfWpe9yAqrQKngqVv 前两个小部件是通过常规 html 标记生成的,后两个是使用 ngRepeat 的小部件。 @Prera​​k Sola 我修改了$scope.dashboardWidgets 数组。检查更新的数组

以上是关于ngRepeat 对自定义指令标签的主要内容,如果未能解决你的问题,请参考以下文章

为啥自定义指令不能立即反映其代码的变化

Vue.js 源码分析(二十三) 高级应用 自定义指令详解

velocity自定义标签和指令

vue15 自定义元素指令标签指令

自定义指令

AngularJS 自定义指令