【发布时间】:2015-03-05 21:39:08
【问题描述】:
我正在开发一个自定义角度指令,其主要目标是显示数据网格。我想允许我的指令的用户将他们自己的 html 单元格模板注入其中,这将覆盖标准单元格呈现机制。我当然可以让用户在 json 配置对象中定义他们的单元格模板,并使用属性将其传输到我的指令中,但我认为更好的方法是让用户直接将他们的模板指定为 HTML。
预期用途
<my-grid config="config" data="data">
<cell field="active">
<!-- User templates given here for specific columns -->
</cell>
</my-grid>
现在,我在指令中使用链接函数的 transclude 方法来收集指令控制器可用的<cell> 模板。
但是 transclude 函数返回的是编译后的 html,而 html 编译的范围当然是使用页面 <my-grid> 的控制器。这意味着注入的单元格模板不可能使用来自给网格指令到位。
为了实现这一点,<cell> 中的所有内容都需要在未编译的情况下注入。但这似乎是不可能的。我什至连接到 compile 方法,看看是否可以直接从 $element 输入参数中获取给定的<cell> 元素,但即使这样也为时已晚。此时,其他包含指令的模板已被包含在内,覆盖了<cell> 元素。
有人对我如何实现我想要做的事情有任何建议吗?
我的指令
angular.module('myApp', [])
.controller('myController', function ($scope) {
'use strict';
// Simplified metadata for the grid structure
$scope.config = {
columns: [{name: 'id'}, {name: 'name'}, {name: 'active'}, {name: 'comment'}]
};
// Provide data for the directive
$scope.data = [
{id: 1, name: 'test1', active: true, comment: 'Contains something'},
{id: 2, name: 'test2', active: false, comment: 'Another comment'}
];
})
.directive('myGrid', ['$timeout', '$compile', function ($timeout, $compile) {
'use strict';
return {
restrict : 'E',
templateUrl : 'grid/templates/gridPanel.html',
transclude : true,
controllerAs : 'gridCtrl',
bindToController: true,
scope : {
config: '=',
data : '='
},
controller : ['$scope', '$element', function ($scope, $element) {
var ctrl = this;
$timeout(function () {
var elToReplace = $('[tpl]', $element);
elToReplace.replaceWith(ctrl.getTemplate($compile(elToReplace.attr('tpl'))($scope)));
});
ctrl.getTemplate = function (column) {
return (ctrl.templates[column] ? ctrl.templates[column] : ctrl.templates['__ALL__']);
}
}],
compile : function compile ($element, $attrs, transclude) {
var origEl = $element; // $element allready contains the directive template here. <cell> is unobtainable.
return function postLink ($scope, $element, $attrs, ctrl, $transclude) {
// This provides a list of <cell> elements, but they are allready compiled in the scope they are provided in.
$transclude(function (overrides) {
ctrl.templates = _.chain(overrides)
.filter(function (content) {
return content.nodeName.toUpperCase() === 'CELL';
})
.indexBy(function (content) {
return $(content).attr('field');
})
.value();
ctrl.templates['__ALL__'] = '<span>{{ row[column.name] }}</span>';
});
}
}
};
}])
.run(['$templateCache', function ($templateCache) {
'use strict';
$templateCache.put('grid/templates/gridPanel.html',
'<div class="panel panel-default">' +
' <header class="panel-heading">' +
' TEST-GRID' +
' </header>' +
' <div class="panel-body">' +
' <table class="table table-condensed">' +
' <thead>' +
' <tr>' +
' <th ng-repeat="column in gridCtrl.config.columns track by column.name">' +
' {{ column.name }}' +
' </th>' +
' </tr>' +
' </thead>' +
' <tbody>' +
' <tr ng-repeat="row in gridCtrl.data track by $index">' +
' <td ng-repeat="column in gridCtrl.config.columns track by column.name">' +
' <span tpl="column"></span>' + // This is where the cell template should be rendered.
' </td>' +
' </tr>' +
' </tbody>' +
' </table>' +
' </div>' +
'</div>');
}]);
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/lodash.js/3.3.1/lodash.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.3.14/angular.min.js"></script>
<div ng-app="myApp" ng-controller="myController">
<div class="container-fluid">
<h2>My grid setup</h2>
<my-grid config="config" data="data">
<cell field="active">
<label class="checkbox">
<input type="checkbox" ng-model="row.active" />
</label>
</cell>
</my-grid>
</div>
</div>
这不起作用。首先,它没有按照应有的方式嵌入模板。它只嵌入了我设置为“默认模板”的内容,并且被嵌入为明文。未编译。如果我尝试在范围内编译它,角度会产生一个不确定的摘要循环。
【问题讨论】:
-
你为什么不让他们给你一个html字符串,然后用它来编译和使用。我不认为我完全理解你想要做什么以及你希望人们如何给你 html。
-
正如我在问题中所说,我可以让他们在 json 配置字符串中注入 HTML 并将其作为属性传递给指令(参见上面的 params=""),但我认为更好的方法是让用户将他们的模板指定为 HTML(参见上面的单元格元素的内容)
-
也许你应该为你的问题创建一个plunker。您可以尝试使用 textarea 而不是将其 html 作为字符串提供给您的单元格,然后您可以编译它。很难说,你的问题和需求都不清楚。
-
包含了一个可运行的代码 sn-p,它描述了我的指令以及它应该如何工作
标签: javascript angularjs templates angularjs-directive