问题 如何将指令动态加载到页面中


我有一个带控制器的html文件和一个带有模板URL的指令。我想在控制器中有条件地加载/编译指令:

控制器:

app.controller('TestController', function TestController($http, $scope, $compile) {

$scope.loadData = function (pageId) {
    var pUrl = <some url>
    $http({
        method: 'GET',
        url: pUrl
    }).success(function (data, status) {
        $scope.pData = data;
        var htm = '<test-directive></test-directive>';
        var elm = angular.element("#id").append(htm);
        $compile(elm)($scope);
    }).error(function (data, status) {
        alert('error');
    });
};

$scope.loadData();

});

指示:

'use strict';

app.directive('testdirective', function ($http) {
var uDirective = {};

uDirective.restrict = 'E';
uDirective.templateUrl = 'js/directives/testdirective.html';
uDirective.controller = function ($scope, $element, $attrs) {
$scope.showDirectiveData();

    $scope.showDirectiveData = function () {
        $scope.directiveDataCollection = <get data>;
    };
};

uDirective.compile = function (element, attributes) {
    // do one-time configuration of element.

    var linkFunction = function ($scope, element, atttributes) {
    };

    return linkFunction;
};

return uDirective;
});

指令中使用的模板

<div>
   <div ng-repeat="directiveData in directiveDataCollection">
      <span><h4>{{directiveData.Title}}</h4></span>
   </div>
</div>

如何编译TestController中的代码,动态加载指令,最后加载内容并在范围中追加内容?


9730
2018-05-09 04:04


起源



答案:


这是一个通用模板供您参考该摘要,并演示了一些Angular概念:

JS

.directive('parentDirective', function(Resource, $compile){
  return {
    restrict: 'E',
    link: function(scope, elem, attrs){
      Resource.loadData().then(function(result){
        scope.data = result.data;
        var htm = '<child-directive></child-directive>';
        var compiled = $compile(htm)(scope);
        elem.append(compiled);
      });
    }
  }
})
.directive('childDirective', function(){
  return {
    restrict: 'E',
    template: '<div>Content: {{data.key}}</div>'
  }
})
.factory('Resource', function($http){
  var Resource = {};

  Resource.loadData = function(){
    return $http.get('test.json');
  }

  return Resource;
})

HTML

<body ng-app="myApp">
  <parent-directive></parent-directive>
</body>

请注意,没有控制器代码。这是因为 控制器永远不应该操纵DOM  - 一个原因是它会使您的代码成为PITA进行测试。所以,我把所有内容放在指令中,它应该也适用于你的情况。

我还将$ http服务移到了工厂。任何状态/模型都应该在服务中。除此之外,通过执行此操作,您几乎可以将其注入任何位置(包括指令内部)以访问数据,而无需担心控制器卸载时它会消失。

编辑

您还应该在接受的答案中考虑动态加载方法的不同观点 动态添加Angular指令


14
2018-05-09 04:43



一个小小的补充:如果子指令具有独立的范围且无法访问 数据 在父控制器中,您可以简单地重写子模板 template: '<div content="data">Content: {{content.key}}</div>'。很棒的解决方案,谢谢@ marc-kline! - bosch
注意:这仅在子指令显式设置模板html时有效。如果您尝试使用templateURL或$ http.get或$ templateRequest从URL加载模板,则无法使用。 - nuander
@nuander奇怪,加载templateUrl使用Angular 1.5为我工作 - Jose Leon


答案:


这是一个通用模板供您参考该摘要,并演示了一些Angular概念:

JS

.directive('parentDirective', function(Resource, $compile){
  return {
    restrict: 'E',
    link: function(scope, elem, attrs){
      Resource.loadData().then(function(result){
        scope.data = result.data;
        var htm = '<child-directive></child-directive>';
        var compiled = $compile(htm)(scope);
        elem.append(compiled);
      });
    }
  }
})
.directive('childDirective', function(){
  return {
    restrict: 'E',
    template: '<div>Content: {{data.key}}</div>'
  }
})
.factory('Resource', function($http){
  var Resource = {};

  Resource.loadData = function(){
    return $http.get('test.json');
  }

  return Resource;
})

HTML

<body ng-app="myApp">
  <parent-directive></parent-directive>
</body>

请注意,没有控制器代码。这是因为 控制器永远不应该操纵DOM  - 一个原因是它会使您的代码成为PITA进行测试。所以,我把所有内容放在指令中,它应该也适用于你的情况。

我还将$ http服务移到了工厂。任何状态/模型都应该在服务中。除此之外,通过执行此操作,您几乎可以将其注入任何位置(包括指令内部)以访问数据,而无需担心控制器卸载时它会消失。

编辑

您还应该在接受的答案中考虑动态加载方法的不同观点 动态添加Angular指令


14
2018-05-09 04:43



一个小小的补充:如果子指令具有独立的范围且无法访问 数据 在父控制器中,您可以简单地重写子模板 template: '<div content="data">Content: {{content.key}}</div>'。很棒的解决方案,谢谢@ marc-kline! - bosch
注意:这仅在子指令显式设置模板html时有效。如果您尝试使用templateURL或$ http.get或$ templateRequest从URL加载模板,则无法使用。 - nuander
@nuander奇怪,加载templateUrl使用Angular 1.5为我工作 - Jose Leon