当各自的转换内容存在时,替换指令模板的部分内容

时间:2016-03-25 19:14:39

标签: javascript html angularjs

我试图执行以下操作:

如果我添加<my-custom-directive></<my-custom-directive>

它应该扩展到

<div class="my-custom-container">
   <label class="my-custom-label">Fallback</label>
   <input class="my-custom-input"/>
</div>

可以通过在DDO中将上述内容设置为templatereplace:true来完成。

如果我在HTML中添加以下内容:

<my-custom-directive>
   <my-custom-label class="users-custom-class"><span>Custom content</span><my-custom-label>
</<my-custom-directive>

它应该扩展到

<div class="my-custom-container">
   <label class="my-custom-label users-custom-class"><span>Custom content</span></label>
   <input class="my-custom-input"/>
</div>

这意味着如果用户想要提供自定义<label><input>等,我们会使用翻译,并且已转换的内容会替换原始模板中的相应广告位,类似于replace:true的方式指令将用它的模板替换自己。

我无法合并replace和翻译功能。

我到目前为止(某些工作状态)的内容如下:

&#13;
&#13;
angular.module('test', [])
  .directive('transTest', function() {
    return {
      transclude: {
        lab: '?labelTest',
        inp: '?inputTest'
      },
      replace: true,
      template: '<div class="container"><label ng-transclude="lab">Fallbacl label</label><input type="text" placeholder="fallback" ng-transclude="inp"></div>',
      link: function(scope, element, attrs, ctrl, transclude) {
        console.log(transclude())
      }
    }
  });
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.2/angular.js"></script>
<div ng-app="test">
  <div trans-test class="test">
    <label-test>test label</label-test>
    <input-test>test input</input-test>
  </div>
</div>
&#13;
&#13;
&#13;

如您所见,已转换的内容位于包含translude的元素内,而不是替换它。我已阅读source code comments文章,并检查了ui-bootstrap-accordion的实施情况,并尝试了transclude:'element'的运气,但它在DOM中没有留下任何内容,只留下评论。

transclusion,replace等是我发现的可用选项,它提供的功能类似于我想要实现的功能。但他们似乎并不能很好地发挥作用。如果可能的话,在角度中实现这种功能的正确方法是什么??

2 个答案:

答案 0 :(得分:5)

看来我终于成功了。解决方案由两部分组成:

  1. 使用类似于回退的模板定义transclude-slot元素的指令(默认)。

    这样做的主要原因是在DDO中设置replace:true时,利用angular的内置功能将属性复制到模板根元素。我不想在链接功能中手动完成。
    另一个原因是它允许您添加其他功能,例如默认模板

  2. 中不需要的转换
  3. 第二步是在模板中不定义 ng-transclude指令,而是使用传递给transclude的{​​{1}}函数来访问被转换的各种广告位的内容,并将相应的元素替换为已转换的内容(如果存在)(使用link

  4. 嗯,这并不容易让我明白,也不容易解释。希望下面的演示比单词解释它更好:

    transclude.isSlotFilled()
    angular.module('test', [])
      .directive('transTest', function() {
        return {
          replace: true,
          transclude: {
            lab: '?labelTest',
            inp: '?inputTest'
          },
          template: '<div class="test-parent"><label class="fallback-label">Fallback </label><br><input type="text" class="fallback-input"></div>',
          link: function(scope, element, attrs, ctrl, transclude) {
            if (transclude.isSlotFilled('lab')) {
              var label = transclude(angular.noop, null, 'lab');
              element.find('label').replaceWith(label);
            }
            if (transclude.isSlotFilled('inp')) {
              var input = transclude(angular.noop, null, 'inp');
              element.find('input').replaceWith(input);
            }
          }
        }
      }).directive('labelTest', function($compile) {
        return {
          template: '<label class="fallback-label ng-transclude">Fallback </label>',
          replace: true,
          transclude: true
        }
      }).directive('inputTest', function($compile) {
        return {
          template: '<input type="text" class="fallback-input">',
          replace: true
        }
      });

答案 1 :(得分:3)

您可能正在寻找更优雅的解决方案,但您可以使用指令的控制器$transclude功能转到find out if a transclusion-slot has been filled

controller: function($transclude, $scope) {
  $scope.fallback = !$transclude.isSlotFilled('lab');

然后,使用该信息来构建模板。

template: '<div class="container">\
  <label ng-if="fallback === true">Fallback label</label>\
  <div ng-if="fallback === false" ng-transclude="lab"></div>\

但是,如果您可以完全定义要转换的内容,

<label-test>
    <label>test label</label>
</label-test>

替换目标内容可能更有意义 - 而不是整个元素:

template: '<div class="container">\
  <div ng-transclude="lab">\
    <label>Fallback label</label>\
  </div>\

这是一个显示两种方法的plunker:http://plnkr.co/edit/EEq5vovFrSW7kG81yWuf?p=preview