【问题标题】:Load component programmatically in angular 1.6以 Angular 1.6 编程方式加载组件
【发布时间】:2018-09-13 21:40:38
【问题描述】:

我有一个 AngularJS 1.6 应用程序,它有一个小部件部分。

小部件部分是一行,包含 3 个小部件,最终用户可以自己配置。他给出了所有可用小部件的列表,他可以选择放置哪个小部件以及放置在何处。

每个小部件都是这样初始化的组件:

(
  function(angular) {

    function Module1Controller() {
      var vm = this;

      // other stuff here
    }

    angular.module("app")
      .component(
        "module1", {
          controller: Module1Controller,
          templateUrl: 'module1.html'
        }  
      );
  }
)(angular)

现在,由于用户可以选择在特定位置渲染哪个小部件,因此该数据来自网络服务。

根据从 WS 收到的数据,我需要能够“激活”一个组件并“停用”所有其他组件。

我的第一个想法是这样做:

控制器:

(
  function(angular) {

    function ModulesController() {
      var vm = this;

      vm.firstModule = 1;
      vm.secondModule = 1;
      vm.thirdModule = 1;

      vm.availableModules = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
    }

    angular.module("app")
      .controller(
        "ModulesController", 
        [
          ModulesController
        ]
      );
  }
)(angular)

查看:

<div class="container-fluid" ng-controller="ModulesController as c">
    <div class="row">
        <div class="col-xs-4"> <!-- third widget area -->
            <module-1 ng-if="c.firstModule == 1"></module-1>
            <module-2 ng-if="c.firstModule == 2"></module-2>
            <module-3 ng-if="c.firstModule == 3"></module-3>
            <module-4 ng-if="c.firstModule == 4"></module-4>
            <module-5 ng-if="c.firstModule == 5"></module-5>
            <module-6 ng-if="c.firstModule == 6"></module-6>
            <module-7 ng-if="c.firstModule == 7"></module-7>
            <module-8 ng-if="c.firstModule == 8"></module-8>
            <module-9 ng-if="c.firstModule == 9"></module-9>
            <module-10 ng-if="c.firstModule == 10"></module-10>
        </div>
        <div class="col-xs-4"> <!-- third widget area -->
            <module-1 ng-if="c.secondModule == 1"></module-1>
            <module-2 ng-if="c.secondModule == 2"></module-2>
            <module-3 ng-if="c.secondModule == 3"></module-3>
            <module-4 ng-if="c.secondModule == 4"></module-4>
            <module-5 ng-if="c.secondModule == 5"></module-5>
            <module-6 ng-if="c.secondModule == 6"></module-6>
            <module-7 ng-if="c.secondModule == 7"></module-7>
            <module-8 ng-if="c.secondModule == 8"></module-8>
            <module-9 ng-if="c.secondModule == 9"></module-9>
            <module-10 ng-if="c.secondModule == 10"></module-10>
        </div>
        <div class="col-xs-4"> <!-- third widget area -->
            <module-1 ng-if="c.thirdModule == 1"></module-1>
            <module-2 ng-if="c.thirdModule == 2"></module-2>
            <module-3 ng-if="c.thirdModule == 3"></module-3>
            <module-4 ng-if="c.thirdModule == 4"></module-4>
            <module-5 ng-if="c.thirdModule == 5"></module-5>
            <module-6 ng-if="c.thirdModule == 6"></module-6>
            <module-7 ng-if="c.thirdModule == 7"></module-7>
            <module-8 ng-if="c.thirdModule == 8"></module-8>
            <module-9 ng-if="c.thirdModule == 9"></module-9>
            <module-10 ng-if="c.thirdModule == 10"></module-10>
        </div>
    </div>
</div>

这行得通,但我觉得这样做是错误的。如果我有 200 个小部件怎么办?我必须写&lt;module-N ng-if="c.firstModule == N"&gt;&lt;/module-N&gt; 200 次(x3 小部件区域),这显然不是解决问题的好方法。

我也想过使用ng-include,但据我所知它只适用于包含模板,我也需要加载相应的控制器。

这是一个 plunker,展示了我正在努力实现的工作示例:https://plnkr.co/edit/uO8SUcmNMOGHcPjc1lWs?p=preview

如您所见,当您更改组合的值时,相应的模块会被替换。

问题是:有没有一种方法可以根据 AngularJS 1.6 中的某些控制器字段来激活特定组件,而无需声明所有这些字段并使用 ng-if

【问题讨论】:

  • &lt;module-1&gt;&lt;/module-1&gt;&lt;div module-1&gt;&lt;/div&gt; 相同)您可以尝试使用"&lt;div " + module[i] + "&gt;&lt;/div&gt;" 在循环中生成和编译您的组件。这是一个带有指令的小Demo
  • @AlekseySolovey 不幸的是,我必须使用组件(公司要求)。另外,我不能任意编译代码,因为 $compile 来自 $scope 并且我在控制器中没有作用域(同样,公司选择避免使用作用域来支持控制器中的“this”)
  • @BackSlash 接收模块作为输入、加载并随后编译它的模块槽指令怎么样(例如,&lt;module-slot module="module-1"&gt;&lt;/module-slot&gt;)?
  • @LenilsondeCastro 很有趣!您能否发布一个示例,说明如何通过知道模块名称来加载模块?
  • 嗯,你必须以最适合你的架构的方式来实现它,这只是一个例子,你可以将任何你想要的东西传递给插槽并在指令内部解决它,我可以告诉你打算使用加载器我推荐 ocLazyLoad 你可以在这里找到一个简单的例子给你一个线索github.com/ocombe/ocLazyLoad/tree/master/examples/simpleExample

标签: javascript angularjs angular-components


【解决方案1】:

正如我在 cmets 部分所建议的,您可以使用 module-slot 指令并将模块作为一种模型输入,并在内部解决所需模块的加载和编译。

此解决方案使用ocLazyLoad,但您可以根据需要使用其他加载程序。

I've made a fork of your plunkr with a solution using ocLazyLoading

因此,与其声明所有模块并使用ng-if 控制其可见性,不如只使用一个指令,如下所示:

<div class="row">
    <div class="col-xs-4">
      <module-slot module="c.firstModule"></module-slot>
    </div>
    <div class="col-xs-4">
      <module-slot module="c.secondModule"></module-slot>
    </div>
    <div class="col-xs-4">
      <module-slot module="c.thirdModule"></module-slot>
    </div>
  </div>

指令:

angular.module("app")
    .directive('moduleSlot', function($ocLazyLoad, $compile) {
      return {
        restrict: 'E',
        scope: {
          module: '='
        },
        link: function(scope, element, attrs) {
          // watch the module change
          scope.$watch('module', function() {
            // load the module
            $ocLazyLoad.load("module" + scope.module + ".js").then(function() {
              // compiles the new component inside the slot
              element.html("<module-" + scope.module + "></module-" + scope.module + ">");
              $compile(element.contents())(scope);

            }, function(e) {
              console.log('errr');
              console.error(e);
            })
          });
        }
      }
    });

参考

OcLazyLoad Docs

Simple Example from ocLazyLoad repository

$compile service docs

【讨论】:

    【解决方案2】:

    这里a plunker showing a solution。 关键是创建一个指令来动态关联模板和控制器

    app.directive("module", ['$compile', '$http', '$controller', '$templateCache', function ($compile, $http, $controller, $templateCache) {
        return {
            restrict: 'E',
            replace: true,
            scope: {
                model: '='
            },
            link: function (scope, element, attrs) {
                scope.$watch("model", function (newValue, oldValue, scope) {
                    if (newValue) {
                        var template = scope.model.id + ".html";
                        $http.get(template, { cache: $templateCache }).then(function (result) {
                            element.html(result.data);
                            element.children().data('$ngControllerController', $controller(scope.model.id + "Ctrl", { $scope: scope }));
                            $compile(element.contents())(scope);
                        });
                    }
                });
            }
        };
    }]);
    

    【讨论】:

      猜你喜欢
      • 2015-10-16
      • 1970-01-01
      • 2014-04-30
      • 2016-09-17
      • 1970-01-01
      • 2017-03-27
      • 2014-08-16
      • 2014-12-02
      • 1970-01-01
      相关资源
      最近更新 更多