AngularJS - 无法在链接函数

时间:2017-04-05 14:37:13

标签: jquery angularjs templates angularjs-directive promise

提防

接受的解决方案将破坏replace: true的指令:HTML不会被替换,正在使用的特定CSS选择器将不再起作用等。

我希望我的指令通过观察从父控制器接收的字符串来动态更改其模板,因此我使用this answer中的$compile和来自{{3}的$observe },但它不起作用,如this small part of an interesting tutorial所示。

关于错误

如果脚本中的AngularJS之前包含jQuery,则replaceWith调用会抛出以下错误:

TypeError: Cannot read property 'ownerDocument' of undefined

但是如果我删除jQuery,强制AngularJS使用它的jqLit​​e,同样的部分会抛出这个错误,让像我这样的jQuery不可知的东西更清楚

TypeError: Failed to execute 'replaceChild' on 'Node': parameter 1 is not of type 'Node'.

即使我很清楚我没有将有效的'Node'类型对象传递给replaceWith,我也不知道如何处理这种情况,因为我期待$compile做这个工作。

我所知道的唯一事情是console.log(tplContent)看起来像这样(我承诺是对的吗?):

Object
{
  config: Object
  data: "<script type="text/ng-template" id="templateId.html">
  ↵  <p>TEMPLATE A</p>
  ↵</script>"
  headers: function (d)
  ng339: 10
  status: 200
  statusText: "OK"
}

,而console.log($compile(tplContent)(scope))返回一个数组,该数组具有与第一个相同的对象且仅包含项目:

[Object]
0: {
  config: Object
  data: "<script type="text/ng-template" id="templateId.html">
  ↵  <p>TEMPLATE A</p>
  ↵</script>"
  headers: function (d)
  ng339: 10
  status: 200
  statusText: "OK"
},
length: 1

我确实想避免使用以下两种后备中的任何一种,你知道我在这里做错了吗?

后退a.k.a.不要告诉我这样做

我知道我可以将指令分成两个指令,ng-if就像这样:

(function() {
  'use-strict';

  angular.module('app')
  .directive('dynamicTemplateA', dynamicTemplate);

  DynTplCtrl.$inject = ['$http', '$templateCache', '$compile', '$parse'];

  function dynamicTemplate($http, $templateCache, $compile, $parse) {
    var directive = {
      restrict: 'E',
      templateUrl: 'template-a.html',
      scope: {},
      bindToController: {
        tpl: '@',
        i: '='
      },
      controller: DynTplCtrl,
      controllerAs: 'dyntplctrl',
      link: linkFunc
    }

    return directive;

    function linkFunc(scope, el, attrs, ctrl) {}
  }

  DynTplCtrl.$inject = [];

  function DynTplCtrl() {}

})()

(function() {
  'use-strict';

  angular.module('app')
  .directive('dynamicTemplateB', dynamicTemplate);

  DynTplCtrl.$inject = ['$http', '$templateCache', '$compile', '$parse'];

  function dynamicTemplate($http, $templateCache, $compile, $parse) {
    var directive = {
      restrict: 'E',
      templateUrl: 'template-b.html',
      scope: {},
      bindToController: {
        tpl: '@',
        i: '='
      },
      controller: DynTplCtrl,
      controllerAs: 'dyntplctrl',
      link: linkFunc
    }

    return directive;

    function linkFunc(scope, el, attrs, ctrl) {}
  }

  DynTplCtrl.$inject = [];

  function DynTplCtrl() {}

})()

然后在controller.html

<div ng-repeat="i in [1,2,3]">
  <dynamic-template-a ng-if="mainctrl.tpl === 'a'" tpl="{{mainctrl.tpl}}" i="i"></dynamic-template-a>
  <dynamic-template-b ng-if="mainctrl.tpl === 'b'" tpl="{{mainctrl.tpl}}" i="i"></dynamic-template-b>
</div>

我也知道我可以使用ng-include this plunkr

(function() {
  'use-strict';

  angular.module('app')
  .directive('dynamicTemplateA', dynamicTemplate);

  DynTplCtrl.$inject = ['$http', '$templateCache', '$compile', '$parse'];

  function dynamicTemplate($http, $templateCache, $compile, $parse) {
    var directive = {
      restrict: 'E',
      template: '<div ng-include="dyntplctrl.getTemplateUrl()"></div>',
      scope: {},
      bindToController: {
        tpl: '@',
        i: '='
      },
      controller: DynTplCtrl,
      controllerAs: 'dyntplctrl',
      link: linkFunc
    }

    return directive;

    function linkFunc(scope, el, attrs, ctrl) {}
  }

  DynTplCtrl.$inject = [];

  function DynTplCtrl() {
    var vm = this;
    vm.getTemplateUrl = _getTemplateUrl;

    function _getTemplateUrl() {
      return 'template-' + vm.tpl + '.html';
    }
  }

})()

2 个答案:

答案 0 :(得分:2)

this question

您需要在替换模板时稍微更改一下代码:

el.html(tplContent.data);
$compile(el.contents())(scope);

这将替换元素的内容(虽然你需要在这里处理清理),然后在指令的范围内编译模板。

此外,为了进行测试,我删除了<script>template-a.html中的template-b.html代码。

以下是forked plunker,其中包含上述更改。

答案 1 :(得分:0)

您不必将HTML放在脚本标记中。只需将纯HTML存储在文件中,如

模板a.html

<p>TEMPLATE A</p>

稍微修改你的代码以达到你想要的效果。

       function(tplContent) {
           var content = $compile(tplContent.data)(scope);
           if(el[0].childNodes.length){
             el[0].removeChild(el[0].childNodes[0]);
           }
          el.append(content);
        }