在AngularJS中以程序方式包含组件

时间:2016-07-26 20:28:09

标签: javascript angularjs

我有一个对象数组。这些对象中的每一个都有一个"组件"具有字符串值的属性。现在我想循环遍历列表并呈现每个引用的组件。循环对象的其他属性应该为组件提供参数(下面不包括在内)。

到目前为止我的解决方案有效,但需要在switch-case中声明允许的元素并创建不需要的包装元素:



angular.module('switchExample', [])
      .controller('ExampleController', ['$scope',
        function($scope) {
          $scope.items = [{
            component: "alpha"
          }, {
            component: "beta"
          }, {
            component: "alpha"
          }];
        }
      ])
      .component('alpha', {
        template: "this is component alpha",
      })
      .component('beta', {
        template: "this is component beta"
      })

<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Example</title>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
</head>

<body ng-app="switchExample">
  <div ng-controller="ExampleController">
    <div ng-repeat="s in items" ng-switch="s.component">
        <alpha ng-switch-when="alpha"></alpha>
        <beta ng-switch-when="beta"></beta>
    </div>
  </div>
</body>

</html>
&#13;
&#13;
&#13;

有没有办法在程序上包含组件而不进行字符串比较和显式调用的往返?

这样的事,也许?:

<div ng-repeat="s in items">
    <component ng-component="s.component"></component>
</div>

甚至更好:

<div ng-repeat="s in items" ng-component="s.component"></div>

或者:

<div ng-component="s.component for s in items"></div>

2 个答案:

答案 0 :(得分:2)

完整文档并在GitHub上下载:https://github.com/hubertgrzeskowiak/angular-component-directive

根据我在下面的回答,我以相当干净和多才多艺的方式重新实现了这一点。演示:http://plnkr.co/edit/uDxIUulQPx4C3s11b5cG?p=preview

用法(请参阅GitHub前全文档):

<component name="expr" args="expr" replace="expt"></component>

...其中“name”表达式必须求值为组件名称(字符串),“args”(可选)必须求值为对象,“replace”(可选)必须求值为布尔值。 args被解包为新组件的属性,因此该对象中的每个值都是一个表达式。如果“replace”为true,则组件将替换为自己。

答案 1 :(得分:0)

  

没有ng-component这样的东西可以无缝地完成。这将最终作为重新编译其内容的指令(更不用说性能损失)。您可以通过搜索“动态指令”

之类的方法熟悉该方法      

estus

谢谢,estus!

我做到了这一点!

您可以在下面看到的自定义指令component根据传递的name参数创建组件,并采用可选的args

示例输入:

<component name="'alpha'"></component>

输出:

<component name="'alpha'">
    <alpha>
        whatever alpha component decides to render in its template
    </alpha>
</component>

使用args:

<component name="'alpha'" args="{foo:'bar', num:42, o:{a:1}}"></component>

输出:

<component name="'alpha'" args="{foo:'bar', num:42, o:{a:1}}">
    <alpha foo="'bar'" num="42" o="{a:1}">
        whatever alpha component decides to render in its template with the given args
    </alpha>
</component>

angular.module('switchExample', [])

.directive('component', ['$compile',
  function($compile) {
    return {
      restrict: 'AEM',
      scope: {
        name: '<',
        args: '<'
      },
      controller: function($scope, $element) {
        var args = $scope.args;
        //console.log(args)
        var argsStr = ""
        if (typeof args !== 'undefined' && args.constructor === Object) {
          for (arg in args) {
            argsStr += ' ' + arg + '="args.' + arg + '"';
          }
        }
        var elem = "<" + $scope.name + argsStr + "></" + $scope.name + ">";
        //console.log(elem)
        var component = $compile(elem)($scope)[0];
        $element.append(component);
      }
    }
  }
])

.controller('ExampleController', ['$scope',
    function($scope) {
      $scope.items = [{
        component: "alpha",
        args: {
          foo: "first elem"
        }
      }, {
        component: "alpha",
        args: {
          foo: "the last one has no foo"
        }
      }, {
        component: "alpha",
        args: {}
      }];
    }
  ])
  .component('alpha', {
    bindings: {
      foo: '<?'
    },
    template: "this is component alpha. foo arg: {{ $ctrl.foo }}"
  })
  .component('beta', {
    template: "this is component beta"
  })
<!doctype html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <title>Example</title>
  <script src="//ajax.googleapis.com/ajax/libs/angularjs/1.5.8/angular.min.js"></script>
</head>

<body ng-app="switchExample">
  <h2>Procedural component</h2>
  <component name="'alpha'"></component>
  <br>
  <component name="'alpha'" args="{foo:'this was passed!', num:123, obj:{}}"></component>
  <br>
  <div component name="'alpha'" args="{foo:'as was this'}"></div>
  <hr>
  <h2>Looping</h2>
  <div ng-controller="ExampleController">
    <div ng-repeat="s in items" ng-switch="s.component">
      <component name="s.component" args="s.args"></component>
    </div>
  </div>
</body>

</html>

我无法摆脱包装我的组件的额外HTML元素,但至少我不需要明确告诉循环允许什么和不允许什么。