【问题标题】:Use component in itself recursively to create a tree递归使用组件本身来创建树
【发布时间】:2017-02-22 17:42:34
【问题描述】:

你知道组件本身可以使用吗?如果是,在哪里阅读?

我有下一个情况: 有 mainItems 列表,每个 Main Item 都有 subItem(看起来像 mainItem),每个 subItem 都可以有它自己的 subItem 等。 所以最好用嵌套,但是怎么用呢?

【问题讨论】:

    标签: angular components


    【解决方案1】:

    更新

    forwardRef() 不再需要,因为directives 已移至NgModule.declarations,因此递归组件不再需要在自身上注册为directives

    Angular 4.x.x Plunker example

    原创

    支持。您只需在其@Component() 装饰器中将组件添加到directives: []。因为装饰器在类之前,并且类在声明之前不能被引用 forwardRef() 是必要的。

    import {Component, forwardRef, Input} from '@angular/core'
    
    @Component({
      selector: 'tree-node',
      template: `
      <div>{{node.name}}</div>
      <ul>
        <li *ngFor="let node of node.children">
          <tree-node  [node]="node"></tree-node>
        </li>
      </ul>
    `
    })
    export class TreeNode {
      @Input() node;
    }
    
    @Component({
      selector: 'my-app',
      template: `
        <div>
          <h2>Hello {{name}}</h2>
          <tree-node [node]="node"></tree-node>
        </div>
      `,
      directives: [TreeNode]
    })
    export class App {
      constructor() {
        this.name = 'Angular2 (Release Candidate!)'
      }
    
      node = {name: 'root', children: [
        {name: 'a', children: []},
        {name: 'b', children: []},
        {name: 'c', children: [
          {name: 'd', children: []},
          {name: 'e', children: []},
          {name: 'f', children: []},
         ]},
      ]};  
    }
    

    Angular 2.0.0-beta.x Plunker example

    另见Inject parent component of the same type as child component

    【讨论】:

    • 谢谢甘特。将立即尝试。没有任何导入 {selgComponent} ??只需添加指令。
    • 你可以使用&lt;template #item let-items&gt;&lt;ng-container *ngFor="let item of items&gt;&lt;template [ngTemplateOutlet]="item" [ngTemplateOutletContext="{$implicit: items?.children}"&gt;&lt;/ng-container&gt;&lt;/template&gt;&lt;ng-container *ngFor="let item of items&gt;&lt;template [ngTemplateOutlet]="item" [ngTemplateOutletContext="{$implicit: items?.children}"&gt;&lt;/ng-container&gt;。不要指望这段代码可以工作,我只是试图在没有提供完整的工作示例的情况下理解这个想法(对不起,没有时间)
    • 感谢会探索这个 :) 并让你知道。为什么我要求单一范围是因为我正在创建一个具有不可预测程度的子节点的上下文菜单。单击任何子节点时,我最终需要在包含上下文菜单的组件中捕获该事件。现在,如果我有递归组件树,因为我们没有在角度 2 中广播将事件从单个节点冒泡到树的父级将是一件痛苦的事情。
    • @jackOfAll 我也有同样的问题,我还需要“保留范围”并找到这个alternative solution using ng-template with ngTemplateOutlet。我仍在体验它,但它看起来很有希望。
    • Plunker 需要此更改才能工作:stackoverflow.com/a/64495115/733092
    【解决方案2】:

    使用ng-template是解决递归DOM问题的最佳方案。

    @Component({
      selector: 'tree-node',
       template: `
         <ng-container *ngTemplateOutlet="tree;context:{node:node}">
         </ng-container>
    
         <ng-template #tree let-node="node">
           <div>{{node.name}}</div>
           <ul *ngIf="node.children && node.children.length > 0">
             <ng-container *ngFor="let child of node.children">
               <li>
                 <ng-container *ngTemplateOutlet="tree;context:{node:child}">
                 </ng-container>
               </li>
             </ng-container>
           </ul>
         </ng-template>
       `
    })
    export class TreeNode {
        @Input() node;
    }
    

    无需将组件添加到directives: [] 中的@Component()

    @Component({
      selector: 'my-app',
      template: `
        <div>
          <h2>Hello {{name}}</h2>
          <tree-node [node]="node"></tree-node>
        </div>
      `
    })
    export class App {
    
      node = {
        name: 'root', children: [
          { name: 'a', children: [] },
          {
            name: 'b', children: [
              { name: 'b-1', children: [] },
              {
                name: 'b-2', children: [
                  { name: 'b-2-1', children: [] },
                  { name: 'b-2-2', children: [] },
                  { name: 'b-2-3', children: [] }
                ]
              }
            ]
          },
          {
            name: 'c', children: [
              { name: 'c-1', children: [] },
              { name: 'c-2', children: [] }
            ]
          },
        ]
      };
    
    }
    

    输出:

      • 一个
      • b
        • b-1
        • b-2
          • b-2-1
          • b-2-2
          • b-2-3
      • c
        • c-1
        • c-2

    HTML:

    <tree-node>
        <div>root</div>
        <ul>
            <li>
                <div>a</div>
            </li>
            <li>
                <div>b</div>
                <ul>
                    <li>
                        <div>b-1</div>
                    </li>
                    <li>
                        <div>b-2</div>
                        <ul>
                            <li>
                                <div>b-2-1</div>
                            </li>
                            <li>
                                <div>b-2-2</div>
                            </li>
                            <li>
                                <div>b-2-3</div>
                            </li>
                        </ul>
                    </li>
                </ul>
            </li>
            <li>
                <div>c</div>
                <ul>
                    <li>
                        <div>c-1</div>
                    </li>
                    <li>
                        <div>c-2</div>
                    </li>
                </ul>
            </li>
        </ul>
    </tree-node>
    

    【讨论】:

      【解决方案3】:

      Angular 4递归组件示例:https://plnkr.co/edit/IrW82ye4NKK8cYEPxsFc?p=preview

      摘自链接示例:

      //our root app component
      import {Component, NgModule, VERSION, Input} from '@angular/core'
      import {BrowserModule} from '@angular/platform-browser'
      
      @Component({
        selector: 'tree-node',
        template: `
        <div>{{node.name}}</div>
        <ul>
          <li *ngFor="let node of node.children">
            <tree-node  [node]="node"></tree-node>
          </li>
        </ul>
      `
      })
      export class TreeNode {
        @Input() node;
      }
      
      @Component({
        selector: 'my-app',
        providers: [],
        template: `
          <div>
            <h2>Hello {{name}}</h2>
            <tree-node [node]="node"></tree-node>
          </div>
        `
      })
      export class App {
        constructor() {
          this.name = 'Angular2 (Release Candidate!)'
        }
      
        node = {name: 'root', children: [
          {name: 'a', children: []},
          {name: 'b', children: []},
          {name: 'c', children: [
            {name: 'd', children: []},
            {name: 'e', children: []},
            {name: 'f', children: []},
           ]},
        ]};  
      }
      
      @NgModule({
        imports: [ BrowserModule ],
        declarations: [ App, TreeNode ],
        bootstrap: [ App ]
      })
      export class AppModule {}
      

      此答案是 社区 wiki,因为示例链接是从 Günter Zöchbauer 的答案中复制而来的。我将代码包含在问题正文中以避免链接失效。

      【讨论】:

      • 由于 Plunker 已经超越了 Angular 4,我必须对 stackoverflow.com/a/64495115/733092 进行更改才能运行此代码。最佳答案也是如此。
      • 如果将 node.name 周围的 div 更改为 span,这样名称会显示在项目符号旁边而不是它们下方的一行。
      猜你喜欢
      • 2016-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-09-21
      相关资源
      最近更新 更多