AngularJS:编译指令的输出

时间:2016-05-03 12:49:28

标签: javascript angularjs compilation

我有一些遗留的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处理程序不起作用。这是有道理的,因为它没有编译到范围。

如何正确编译新元素并将其添加到表中?

2 个答案:

答案 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) );
}