Skip to main content
 首页 » 编程设计

jquery之AngularJS之无法在链接函数中动态更改指令模板

2026年04月16日6266hnrainll

小心

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

<小时 />

我希望我的指令通过观察从父 Controller 作为属性接收的字符串来动态更改其模板,因此我使用了 this answer 中的 $compile与 this small part of an interesting tutorial 中的 $observe 一起使用,但是唉它不起作用,如this plunkr所示.

关于错误

如果脚本中 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) 看起来像这样(我的 promise 是对的吗?):

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 

我确实想避免使用以下两个后备方案中的任何一个,您知道我在这里做错了什么吗?

<小时 />

后备又名不告诉我这样做

我知道我可以将指令拆分为两个指令,然后 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 like this :

(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'; 
    } 
  } 
 
})() 

请您参考如下方法:

感谢 this question 。

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

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

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

此外,为了进行测试,我删除了 <script>来自 template-a.html 的标签,和template-b.html .

这是一个forked plunker其中有上述更改。