我有一些遗留的angularjs代码,它使用指令创建动态表,其中控制器可以覆盖表的行为(关于如何显示数据)
它包含以下设置(简化):
.directive('datatable', [function () {
return {
scope: {
items: '=',
tablemetadata: '=',
processors: '=?'
},
controller: ...
$scope.processField = function processField(item, data){
if($scope.processors === undefined){return;}
for(var i = 0; i < $scope.processors.length; i++){
if($scope.processors[i].field===field){
var newData = $scope.processors[i].processor(item, data);
return $sce.trustAsHtml(newData);
}
}
return data;
};
...
<tr ng-repeat="item in items">
<td ng-repeat="column in tableMetadata.columns" ng-bind-html="processField(column.field, $eval('item.'+column.field))"></td>
</tr>
$scope.myItems = [{id: 2, otherProperty: "text"}];
$scope.tableMetadata = {
columns: [
{field: 'id', headerKey: 'object id'},
{field: 'otherProperty', headerKey: 'some data'},
]
};
$scope.tableProcessors = [
{field: 'id', processor: function(entry, data){ //data = content of object.id
var retVal = "<a ng-click='alert(" + data + ");'>click me</a>";
return retVal;
}}
];
<datatable items="myItems" tablemetadata="tableMetadata" processors="tableProcessors"></datatable>
我需要为某些特定属性生成按钮(或其他html元素),例如链接(如上所示)。
显示按钮但ng-click处理程序不起作用。这是有道理的,因为它没有编译到范围。
如何正确编译新元素并将其添加到表中?
答案 0 :(得分:1)
一个简单的解决方案可以是不使用隔离范围。 将范围从范围更改为:{...}到范围:true并使用$ scope。$ eval来评估您的属性。
另一种解决方案(最优雅)可以是使用angularjs transclusion(参见here)。但是这个解决方案要求修改你的指令的dom表示。
答案 1 :(得分:1)
在指令的link
方法中,您必须使用
elem.append( $compile(html)(scope) );
至于干净地分离关注点,我会使每个<td>
自己的指令继承你当前在其隔离范围属性中作为字符串连接的内容。而不是
var retVal = "<a ng-click='alert(" + data + ");'>click me</a>";
<tr ng-repeat="item in items">
<td ng-repeat="column in tableMetadata.columns" ng-bind-html="processField(column.field, $eval('item.'+column.field))"></td>
</tr>
使用类似的东西:
<tr ng-repeat="item in items">
<table-item ng-repeat="..." process-field="item"></table-item>
</tr>
/** directive compiles dynamically */
scope: {
processField: '='
},
link: function(scope, elem, attr, ctrl) {
var template = `<a ng-click="${ctrl.processField}"></a>`;
elem.append( $compile(template)(scope) );
}