如何使用插值指定元素指令?

时间:2019-03-31 11:27:00

标签: angularjs angularjs-directive

我想在angular.js中创建一个视图,在其中添加动态模板集,每个模板都包装在一个指令中。伪指令名称对应于一组对象中的某些字符串属性。我需要一种添加指令的方式,而无需事先知道将需要哪些指令。

该项目将Angular 1.5与webpack结合使用。

这是代码的简化版本:

对象集:

$scope.items = [
    { name: "a", id: 1 },
    { name: "b", id: 2 }
]

指令:

angular.module('myAmazingModule')
    .directive('aDetails', () => ({
        scope: false,
        restrict: 'E',
        controller: 'myRavishingController',
        template: require("./a.html")
    }))
    .directive('bDetails',() => ({
        scope: false,
        restrict: 'E',
        controller: 'myRavishingController',
        template: require("./b.html")
    }));

视图:

<li ng-repeat="item in items">
    <div>
        <{{item.name}}-details/>
    </div>
</li>

,以便最终呈现的视图如下所示:

<li ng-repeat="item in items">
    <div>
        <a-details/>
    </div>
    <div>
        <b-details/>
    </div>
</li>

我该怎么做?

我不介意其他方法,只要我可以内嵌细节模板,然后通过http分别获取它们即可。

3 个答案:

答案 0 :(得分:0)

使用ng-include

<li ng-repeat="item in items">
   <div ng-controller="myRavishingController"
        ng-include="'./'+item.name+'.html'">
   </div>
</li>

  

我想内联它以避免http呼叫。

通过以下两种方式之一将模板直接加载到模板缓存中,从而避免http调用:

  • 在脚本标签中,
  • 或直接使用$templateCache服务。

有关更多信息,请参见

答案 1 :(得分:0)

您可以使用以下指令添加任何html:

const el = $compile(myHtmlWithDirectives)($scope);
$element.append(el);

但是通常这不是最好的方法,我将使用ng-include(为您实际调用$compile)给出更详细的答案:

添加模板,例如在module.run中:[您也可以在html中添加模板,但是当需要在多个位置使用它们时,我更喜欢直接添加它们]

app.module('myModule').run($templateCache => {
  $templateCache.put('tplA', '<a-details></a-details>'); // or webpack require
  $templateCache.put('tplB', '<b-details></b-details>');
  $templateCache.put('anotherTemplate', '<input ng-model="item.x">');
})

您现在的模型是:

$scope.items = [
    { name: "a", template: 'tplA' },
    { name: "b", template: 'tplB' },
    { name: "c", template: 'anotherTemplate', x: 'editableField' }
]

和html:

<li ng-repeat="item in items">
   <div ng-include="item.template">
   </div>
</li>

答案 2 :(得分:0)

为了使用动态指令,您可以像在此plunkr中一样创建一个自定义指令:

https://plnkr.co/edit/n9c0ws?p=preview

这是所需指令的代码:

app.directive('myProxy', function($compile) {
  return {
    template: '<div>Never Shown</div>',
    scope: {
      type: '=',
      arg1: '=',
      arg2: '='
    },
    replace: true,
    controllerAs: '$ctrl',
    link: function($scope, element, attrs, controller, transcludeFn) {
      var childScope = null;

      $scope.disable = () => {
        // remove the inside
        $scope.changeView('<div></div>');
      };

      $scope.changeView = function(html) {
        // if we already had instanciated a directive
        // then remove it, will trigger all $destroy of children
        // directives and remove
        // the $watch bindings
        if(childScope)
          childScope.$destroy();

        console.log(html);

        // create a new scope for the new directive
        childScope = $scope.$new();
        element.html(html);
        $compile(element.contents())(childScope);
      };

      $scope.disable();
    },
    // controller is called first
    controller: function($scope) {

      var refreshData = () => {
        this.arg1 = $scope.arg1;
        this.arg2 = $scope.arg2;
      };

      // if the target-directive type is changed, then we have to 
      // change the template
      $scope.$watch('type', function() {
        this.type = $scope.type;

        refreshData();

        var html = "<div " + this.type + " ";
        html += 'data-arg1="$ctrl.arg1" ';
        html += 'data-arg2="$ctrl.arg2"';
        html += "></div>";

        $scope.changeView(html);
      });

      // if one of the argument of the target-directive is changed, just change
      // the value of $ctrl.argX, they will be updated via $digest
      $scope.$watchGroup(['arg1', 'arg2'], function() {
        refreshData();
      });
    }
  };
});

总体思路是:

  • 我们希望data-type能够指定要显示的指令的名称
  • 其他声明的参数将传递给目标指令。
  • 首先,在链接中,我们声明一个能够通过$ compile创建子指令的函数。 “ link”是在控制器之后调用的,因此在控制器中,您必须以异步方式(在$ watch中)调用它
  • 第二,在控制器中:
    • 如果指令的type发生了变化,我们将重写html以调用目标指令
    • 如果其他参数已更新,我们只需更新$ ctrl.argX,angularjs将在子级中触发$ watch并正确更新视图。

如果您的目标指令都共享相同的参数,则此实现是可以的。我没有走得更远。

如果您想对其进行更动态的修改,我想您可以设置scope: true并必须使用attrs来找到传递给目标指令的参数。

此外,您应该使用https://www.npmjs.com/package/gulp-angular-templatecache之类的模板来转换可连接到javascript应用程序中的代码中的模板。这样会更快。