在 angular 1.6 中以编程方式加载组件 [英] Load component programmatically in angular 1.6

查看:25
本文介绍了在 angular 1.6 中以编程方式加载组件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

小部件部分是一行 3 个小部件,最终用户可以自行配置.他得到了所有可用小部件的列表,他可以选择放置哪个小部件和位置.

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

(功能(角度){函数 Module1Controller() {var vm = 这个;//这里的其他东西}angular.module("应用程序").成分(模块1",{控制器:Module1Controller,templateUrl: 'module1.html'});})(角度)

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

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

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

控制器:

(功能(角度){功能模块控制器(){var vm = 这个;vm.firstModule = 1;vm.secondModule = 1;vm.thirdModule = 1;vm.availableModules = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];}angular.module("应用程序").控制器("模块控制器",[模块控制器]);})(角度)

查看:

<div class="row"><div class="col-xs-4"><!-- 第三个小部件区域--><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 class="col-xs-4"><!-- 第三个小部件区域--><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 class="col-xs-4"><!-- 第三个小部件区域--><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>

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

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

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

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

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

解决方案

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

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

我已经使用 ocLazyLoading 为您的 plunkr 制作了一个分支

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

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

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

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

指令:

angular.module("app").directive('moduleSlot', function($ocLazyLoad, $compile) {返回 {限制:'E',范围: {模块:'='},链接:函数(范围,元素,属性){//观察模块变化scope.$watch('module', function() {//加载模块$ocLazyLoad.load("module" + scope.module + ".js").then(function() {//编译槽内的新组件element.html("<module-" + scope.module + "></module-" + scope.module + ">");$compile(element.contents())(scope);}, 函数(e) {console.log('errr');控制台错误(e);})});}}});

<块引用>

参考

OcLazyLoad 文档

来自 ocLazyLoad 存储库的简单示例

$compile 服务文档

I have an AngularJS 1.6 application which has a widget section.

The widget section is a row with 3 widget that the end user can configure himself. He's given a list of all available widget, and he can choose which one to place and where.

Every widget is a component initialized like so:

(
  function(angular) {

    function Module1Controller() {
      var vm = this;

      // other stuff here
    }

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

Now, since the user can select which widget to render in a specific position, this data comes from a webservice.

Based on the data received from the WS, I need to be able to "activate" a component and "deactivate" all other components.

My first thought was to do something like so:

Controller:

(
  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)

View:

<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>

This works, but I feel it's the wrong way to do it. What if I have 200 widgets? I would have to write <module-N ng-if="c.firstModule == N"></module-N> 200 times (x3 widget areas), which is clearly not a good way to solve the issue.

I also thought to use ng-include, but as faras I know it only works for including templates, I need the corresponding controller to get loaded too.

Here is a plunker showing a working example of what I'm trying to achieve: https://plnkr.co/edit/uO8SUcmNMOGHcPjc1lWs?p=preview

As you can see, when you change the value of a combo, the corresponding module gets replaced.

The question is: is there a way to activate a specific component based on some controller field in AngularJS 1.6 without having to declare all of them and use ng-if?

解决方案

As I suggested in the comments section, you can use a module-slot directive and input the module as a sort of model, and internally resolve either the loading and compilation of the desired module.

This solution uses ocLazyLoad but you can use other loader if you want.

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

So, instead of declaring all modules and control its visibility with ng-if you use only one directive like so:

<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>

Directive:

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

Refs

OcLazyLoad Docs

Simple Example from ocLazyLoad repository

$compile service docs

这篇关于在 angular 1.6 中以编程方式加载组件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
前端开发最新文章
热门教程
热门工具
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆