【问题标题】:Angular - getting ng-bind to work on nested directivesAngular - 让 ng-bind 处理嵌套指令
【发布时间】:2017-04-08 23:07:30
【问题描述】:

我已经构建了一个小模式,可以根据模型递归地创建不同的子指令。我正在使用 $compile 递归地构建子指令,然后将它们附加到父指令。
指令构建本身似乎工作得很好,但由于某种原因,嵌入式表达式或ng-bind 或插值似乎不适用于嵌套指令。

这是一个sn-p:

app.directive("child", function ($compile) {
  function getTemplate(depth) {
    if (depth % 2 == 0) {
      return "<even depth='deeper'/>"
    } else {
      return "<odd depth='deeper'/>"
    }
  }
  return {
    scope: {
      depth: "="
    },
    link: function linker($scope, $element) {
      if ($scope.depth == 0) {
        var child = angular.element("<span ng-bind='depth'/>");
        child = $compile(child)($scope);
        $element.append(child);
      } else {
        $scope.deeper = $scope.depth - 1;
        var child = angular.element(getTemplate($scope.depth));
        child = $compile(child)($scope);
        $element.append(child);
      }
    }
  }
})

基本上在这个测试中,指令会递归地向下跳,直到depth 到达0,然后吐出一个&lt;span&gt; 元素。
预期的结果应该是一个值为0 的span 元素。但是好像没有评价。使用 &lt;span&gt;{{depth}}&lt;/span&gt; 还会生成文字 html,而不是评估内容。
我正在尝试实现嵌套&lt;even&gt;&lt;odd&gt;&lt;even&gt; 指令的结果删除 周围的&lt;child&gt; - 指令。

这是一个完整的 jsFiddle:https://jsfiddle.net/eg1e1aLz/

生成的 DOM 应该如下所示:

<test depth="4" class="ng-isolate-scope">
  <even depth="depth-1" class="ng-scope ng-isolate-scope">
    <odd depth="depth-1" class="ng-scope ng-isolate-scope">
      <even depth="depth-1" class="ng-scope ng-isolate-scope">
        <odd depth="depth-1" class="ng-scope ng-isolate-scope"><span ng-bind="depth" class="ng-binding ng-scope">0</span></odd>
      </even>
    </odd>
  </even>
</test>

【问题讨论】:

  • 您希望evenodd 标记如何调用child 指令?
  • 对不起,忘了提琴...
  • 你期待什么类型的输出@Michael

标签: angularjs


【解决方案1】:

根据您下面的 cmets 和对问题的更新,以下如何...

它使用模板函数getTemplate 来构建结构,并使用相同的指令:oddeven 作为占位符来构建功能。

var app = angular.module("app", []);

app.directive("test", function($compile) {
  return {
    scope: {
      depth: "="
    },
    link: function linker($scope, $element, $attrs) {

      // template accessible to the child directives
      $scope.getTemplate = function(depth) {
        if (depth <= 0) {
          return "<span ng-bind='depth'/>"; // also bindings like {{depth}} work
        } else if (depth % 2 === 0) {
          return "<even depth='depth-1'></even>"; // bindings like {{depth}} work
        } else {
          return "<odd depth='depth-1'></odd>";
        }
      }

      var child = angular.element($scope.getTemplate($scope.depth));
      $compile(child)($scope);
      $element.append(child);
    }
  }
});
app.directive("odd", function($compile) {
  return {
    scope: {
      depth: "="
    },
    link: function linker($scope, $element) {
      $scope.getTemplate = $scope.$parent.getTemplate; // bring template into current scope
      var child = angular.element($scope.getTemplate($scope.depth));
      $compile(child)($scope);
      $element.append(child);
    }
  }
})
app.directive("even", function($compile) {
  return {
    scope: {
      depth: "=",
    },
    link: function linker($scope, $element) {
      $scope.getTemplate = $scope.$parent.getTemplate; // bring template into current scope
      var child = angular.element($scope.getTemplate($scope.depth));
      $compile(child)($scope);
      $element.append(child);
    }
  }
})

var controller = app.controller("controller", function($scope) {});

更新小提琴:https://jsfiddle.net/bda411fj/15/

结果:

<test depth="4" class="ng-isolate-scope">
  <even depth="depth-1" class="ng-binding ng-scope ng-isolate-scope">
    <odd depth="depth-1" class="ng-binding ng-scope ng-isolate-scope">
      <even depth="depth-1" class="ng-binding ng-scope ng-isolate-scope">
        <odd depth="depth-1" class="ng-binding ng-scope ng-isolate-scope">
          <span ng-bind="depth" class="ng-binding ng-scope">0</span>
        </odd>
      </even>
    </odd>
  </even>
</test>

【讨论】:

  • 不幸的是,这不是我正在寻找的解决方案。我想要做的是摆脱“子”元素。我想要一个动态模板指令,用孩子替换自己。
  • 好的,我想我明白了。我再看看
  • 您是否正在寻找 test 以递归方式调用自身?你还想保持奇数/偶数吗?
  • 你的意思是像jsfiddle.net/353gtrpd/3(删除了child指令)
  • 更新了答案以使用单个递归指令,该指令将在深度 0 (jsfiddle.net/353gtrpd/4) 处吐出跨度。 NgBind 工作在最低级别(跨度)。如果这不是您想要的,也许您可​​以澄清您的预期输出
【解决方案2】:

模板的编译部分只需要在 child.html() 上引用为子级。
将 3 个地方的代码从 $element.append(child.html()); 更改为 $element.append(child);

这将开始打印您正在寻找的深度值。你还有什么要找的吗?

【讨论】:

    【解决方案3】:

    您的 html 可能没有经过清理,这就是它无法编译的原因 尝试使用 ngSanatize ti 可能会解决您的问题 https://docs.angularjs.org/api/ngSanitize/service/$sanitize 它会删除所有潜在危险的标记并返回正确的 html .

    【讨论】:

      【解决方案4】:

      既然你不想使用 html(),就不要使用 child.html()。

      使用孩子本身。

      在此处查看文档

      检查下面的sn-p。根据您问题中的示例 sn-p 添加

      var app = angular.module("app", []);
      app.directive("test", function($compile) {
        return {
          scope: {
            depth: "="
          },
          link: function linker($scope, $element, $attrs) {
            var child = angular.element("<child depth='depth'/>");
            child = $compile(child)($scope);
            $element.append(child);
          }
        }
      });
      app.directive("child", function($compile) {
        function getTemplate(depth) {
            return depth % 2 == 0 ? "<even depth='depth-1'/>" : "<odd depth='depth-1'/>"
        }
        return {
          scope: {
            depth: "="
          },
          link: function linker($scope, $element) {
            if ($scope.depth == 0) {
              var child = angular.element("<span ng-bind='depth'/>");
              child = $compile(child)($scope);
              $element.append(child);
            } else {
              var child = angular.element(getTemplate($scope.depth));
              child = $compile(child)($scope);
              $element.append(child);
            }
          }
        }
      })
      app.directive("odd", function($compile) {
        return {
          scope: {
            depth: "="
          },
          link: function linker($scope, $element) {
            var child = angular.element("<child depth='depth'/>");
            child = $compile(child)($scope);
            $element.append(child);
          }
        }
      })
      app.directive("even", function($compile) {
        return {
          scope: {
            depth: "="
          },
          link: function linker($scope, $element) {
            var child = angular.element("<child depth='depth'/>");
            child = $compile(child)($scope);
            $element.append(child);
          }
        }
      })
      var controller = app.controller("controller", function($scope) {});
      body {
        padding: 5px 5px 5px 5px !important;
        font-size: 30px;
      }
      
      test,
      child,
      even,
      odd {
        padding: 5px 5px 5px 5px;
        margin: 5px 5px 5px 5px;
        border: 1px solid black;
      }
      
      test {
        background-color: aliceblue !important;
      }
      
      child {
        background-color: beige !important;
      }
      
      even {
        background-color: lightgreen !important;
      }
      
      odd {
        background-color: lightcoral !important;
      }
      <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.4.8/angular.min.js"></script>
      <body ng-app="app" ng-controller="controller">
        <test depth="4"></test>
      </body>

      【讨论】:

        【解决方案5】:

        你的 jsfiddle 很好,唯一的问题是有点逻辑。

        当你编译子指令时,你不应该附加child.html(),因为这将附加一个没有绑定和连接到它们的观察者的HTML。相反,您应该附加整个孩子

        https://jsfiddle.net/eg1e1aLz/2/

        child = $compile(child)($scope);
        $element.append(child);
        

        【讨论】:

          【解决方案6】:

          很抱歉,如果我错过了您要完成的任务的上下文,但我认为您不需要使用子指令或类似的东西。您可以只使用 test 指令并不断构建孩子,然后将范围绑定到最后一个:

          angular.module("app", [])
              .directive("test", function ($compile) {
                  return {
                      scope: {
                          depth: "="
                      },
                      link: function linker($scope, $element, $attrs) {
                          var element = $element;
                          for (var x = 0; x < $scope.depth; x++) {
                              var elementType = x % 2 === 0 ? 'even' : 'odd';
                              var subElement = angular.element(document.createElement(elementType));
                              element.append(subElement);
                              element = subElement;
                          }
                          var span = angular.element('<span ng-bind="depth" />');
                          element.append(span);
                          $compile(span)($scope);
                      }
                  }
              })
          

          小提琴:https://jsfiddle.net/ffyv0zmy/

          我意识到在您的示例中,您希望输出的深度为“0”,但您可以对其进行硬编码,因为我不确定它的用途。

          生成的 HTML:

          <test depth="4" class="ng-isolate-scope">
              <even>
                  <odd>
                      <even>
                          <odd>
                              <span ng-bind="depth" class="ng-binding ng-scope">4</span>
                          </odd>
                      </even>
                  </odd>
              </even>
          </test>
          

          这样做的好处是您不必将范围附加到偶数/奇数元素,除非您也想这样做。

          您仍然可以将指令连接到每个奇数/偶数元素,但是您必须对 $element 进行 $compile 以附加所有范围。

          【讨论】:

            猜你喜欢
            • 2015-05-06
            • 2013-06-29
            • 2021-07-25
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多