如何使用 Angular 2、4、5、6、7、8、9 创建层次结构

普拉莫德·库马尔·夏尔马

我想使用Angular 2 或 Angular 4从 json 文件创建层次结构位置的层次结构可能会根据要求而改变。任何人都可以建议我如何创建所需的模板。下面提到了可能的情况。

文件名:location.json

{
  "name" : "India",
  "children" : 
      {
         "name" : "Karnataka",
         "children" : 
             {
                "name" : "Banglore",
                "children" : 
                   [
                     {"val" : "silk"},
                     {"val" : "agara"}
                   ]                                         
             }
       }
},
 {
  "name" : "India",
  "children" : 
       {
         "name" : "goa",
         "children" : 
             [
                {"val" : "panji"},
                {"val" : "abc"}
             ]                                         
      }
}

情况1

<div> India
  <div> Karnataka
    <div> Banglore
      <div> silk </div>
      <div> agara </div>
    </div>
  </div> 
</div>
<div> India 
  <div> goa
    <div> panji</div>
    <div> abc</div>
   </div>
 </div>

普拉莫德·库马尔·夏尔马

我正在共享用于设计层次结构的工作代码。

注意编译hierarchy.component.scss需要node-sass

安装 node-sass :npm install node-sass


层次结构.component.ts

import { Component, OnInit, Input, OnChanges, SimpleChanges, SimpleChange, Output, EventEmitter } from '@angular/core';
import { Node } from './hierarchy.model';

@Component({
  selector: 'app-hierarchy',
  templateUrl: './hierarchy.component.html',
  styleUrls: ['./hierarchy.component.scss']
})
export class HierarchyComponent implements OnInit, OnChanges {
  @Input() name: string;
  @Input() data: Array<Node>;
  @Input() selectedNodeIds: Array<string> = [];
  @Output() selectedIds: EventEmitter<Array<string>> = new EventEmitter<Array<string>>();

  public hierarchyData: Array<Node>;
  public showHiearchy: boolean;
  private actingNode: string;


  constructor() {
    this.name = 'Hierarchy';
    this.showHiearchy = false;
    this.hierarchyData = new Array<Node>();
  }

  ngOnInit(): void {}

  // go to parent and set full or partial select. Their method.
  private setParentFullOrPartialSelected(isChecked: boolean, node: Node, parent: Node) {
    if (isChecked) {
      if (parent) {
        if (this.checkAllChildOfNodeSelected(parent)) {
          parent.allSelected = true;
          this.setParentFullOrPartialSelected(isChecked, parent, parent.parentRef);
        } else {
          this.removeAllSelected(parent);
        }
      }
    } else {
      this.removeAllSelected(node);
      this.setParentPartialSelected(node);
    }
  }

  private checkAllChildOfNodeSelected(parentNode: Node): boolean {
    const nodes: Array<Node> = parentNode.children;
    let condition = true;
    (Array.isArray(nodes)) ? condition = nodes.every((node: Node) => this.isAllSelected(node)) : null;
    return condition;
  }

  public isAllSelected(node: Node): boolean {
    const condition = node.allSelected ? node.allSelected : true;
    return condition && (node.allSelected);
  }

  private removeAllSelected(node: Node) {
    node.allSelected ? node.allSelected = false : null;
  }

  private setParentPartialSelected(node: Node) {
    if (node.parentRef) {
      node.parentRef.allSelected ? node.parentRef.allSelected = false : null;
      this.setParentPartialSelected(node.parentRef);
    }
  }


  // Update parents and their method
  private updateParents(isChecked: boolean, node: Node) {
    const parent = node ? node.parentRef : null;
    if (parent) {
      if (isChecked) {
        parent.checked = isChecked;
        this.updateParents(isChecked, parent);
      } else {
        if (!this.isSomeChildOfNodeSelected(parent)) {
          parent.checked = isChecked;
          if (this.isSelected(parent)) {
            this.removeSelectedNodeId(parent);
          }
          this.updateParents(isChecked, parent);
        }
      }
    }
  }

  private isSomeChildOfNodeSelected(parentNode: Node): boolean {
    const nodes: Array<Node> = parentNode.children;
    let condition = false;
    (Array.isArray(nodes)) ? condition = nodes.some((node: Node) => node.checked) : null;
    return condition;
  }

  public checkboxChanged(isChecked: boolean, node: Node, parent: Node = null) {
    node.checked = isChecked;
    node.parentRef = parent;
    this.actingNode = node.id;
    node.allSelected = isChecked;
    // go to parent and set full or partial select.
    this.setParentFullOrPartialSelected(isChecked, node, parent);
    // go to parent and make them checked or unchecked.
    this.updateParents(isChecked, node);
    // go to child and select them or de-select.
    this.updateChildrens(isChecked, node);
    this.updateSelectedNodeIds(isChecked, node);
    this.selectedIds.emit(this.selectedNodeIds);
  }


  private updateChildrens(isChecked: boolean, node: Node) {
    const childNodes: Array<Node> = node.children;
    if (childNodes) {
      // tslint:disable-next-line: prefer-for-of
      for (let i = 0; i < childNodes.length; i++) {
          childNodes[i].checked = isChecked;
          childNodes[i].allSelected = isChecked;
          if (isChecked) {
            this.updateSelectedNodeIds(isChecked, childNodes[i]);
          } else {
            this.removeSelectedNodeId(childNodes[i]);
          }
          this.updateChildrens(isChecked, childNodes[i]);   // use recursion to update childrens within children.
      }
    }
  }

  private updateSelectedNodeIds(isChecked: boolean, node: Node) {
    if (isChecked) {
      if (!this.isSelected(node)) {
        this.selectedNodeIds.push(node.id);
      }
    } else {
      this.removeSelectedNodeId(node);
    }
  }

  private removeSelectedNodeId(node: Node) {
    if (this.isSelected(node)) {
      const index = this.selectedNodeIds.indexOf(node.id);
      this.selectedNodeIds.splice(index, 1);
    }
  }

  public isPartiallySelected(node: Node) {
      return node.checked && !node.allSelected;
  }

  public isSelected(node: Node): boolean {
    if (this.selectedNodeIds) {
      return this.selectedNodeIds.indexOf(node.id) > -1;
    }
    return false;
  }

  public toggleHierarchy() {
    this.showHiearchy = !this.showHiearchy;
  }

  public expandNode(node: Node) {
    node.expanded = !node.expanded;
  }

  /**
   *  For each node it will set referance to parent node and also ensure to initilize the variables.
   * @param nodes List of node.
   * @param parentNode parent of node.
   */
  public setNodeDefault(nodes: Array<Node>, parentNode: Node = null) {
    nodes.forEach( (node: Node) => {
      node.allSelected = false;
      node.checked = false;
      node.expanded = true;
      node.parentRef = parentNode;
      if (node.children) {
        this.setNodeDefault(node.children, node);
      }
    });
  }

  ngOnChanges(changes: SimpleChanges) {
    const dataChange: SimpleChange = changes['data'];

    if (dataChange && dataChange.currentValue) {
      this.hierarchyData = new Array<Node>( new Node('all', 'Select All', this.data));
      // If select all is not required, then comment above line and use below line code
      //  this.hierarchyData = this.data;
      this.setNodeDefault(this.hierarchyData);
    }
  }

}

层次结构.component.html

<div class="flex-inline-col dropdown">
    <div class="dropdown__btn" (click)=toggleHierarchy()>{{name}}</div>
    <div class="dropdown__content" [class.toggle-drop-down]="showHiearchy">
        <div class="dropdown__search">
            <input type="text" class="dropdown__search" autofocus>
        </div>
        <ul class="dropdown__hierarchy">
            <li class="dropdown__hierarchy__list">
                <ul class="hierarchy">
                    <ng-container *ngTemplateOutlet="hierarchyNode; context: {$implicit: hierarchyData, level: 'first'}"></ng-container>
                </ul>
            </li>
        </ul>
    </div>
</div>

<ng-template #hierarchyNode let-hierarchyData let-level="level" let-parent="parent">
    <li *ngFor="let node of hierarchyData" [class.last-children]="!node.children"
        class="flex-col hierarchy__item">
        <div>
            <div *ngIf="node.children" class="flex-inline hierarchy__item__icon" (click)="expandNode(node)">
                <svg *ngIf="!node.expanded" version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
                    <title>circle-right</title>
                    <path d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 29c-7.18 0-13-5.82-13-13s5.82-13 13-13 13 5.82 13 13-5.82 13-13 13z"></path>
                    <path d="M11.086 22.086l2.829 2.829 8.914-8.914-8.914-8.914-2.828 2.828 6.086 6.086z"></path>
                </svg>
                <svg *ngIf="node.expanded"  version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
                    <title>circle-down</title>
                    <path d="M32 16c0-8.837-7.163-16-16-16s-16 7.163-16 16 7.163 16 16 16 16-7.163 16-16zM3 16c0-7.18 5.82-13 13-13s13 5.82 13 13-5.82 13-13 13-13-5.82-13-13z"></path>
                    <path d="M9.914 11.086l-2.829 2.829 8.914 8.914 8.914-8.914-2.828-2.828-6.086 6.086z"></path>
                </svg>
            </div>
            <input type="checkbox" id="check_{{node.id}}"
                class="flex-inline hierarchy__item__checkbox"
                [checked]="node.checked || isSelected(node)"
                (change)="checkboxChanged($event.target.checked, node, parent)">
            <label for="check_{{node.id}}" class="flex-inline hierarchy__item__label">
                <span class="hierarchy__item__icon hierarchy__item__circle" *ngIf="!node.checked">
                    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
                        <title>radio-unchecked</title>
                        <path d="M16 0c-8.837 0-16 7.163-16 16s7.163 16 16 16 16-7.163 16-16-7.163-16-16-16zM16 28c-6.627 0-12-5.373-12-12s5.373-12 12-12c6.627 0 12 5.373 12 12s-5.373 12-12 12z"></path>
                    </svg>
                </span>
                <span class="hierarchy__item__icon hierarchy__item__circle-checked" *ngIf="node.checked && node.allSelected">
                    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
                        <title>checkmark</title>
                        <path d="M21.82 13.030l-1.002-1.002c-0.185-0.185-0.484-0.185-0.668 0l-6.014 6.013-2.859-2.882c-0.186-0.185-0.484-0.185-0.67 0l-1.002 1.003c-0.185 0.185-0.185 0.484 0 0.668l4.193 4.223c0.185 0.184 0.484 0.184 0.668 0l7.354-7.354c0.186-0.185 0.186-0.484 0-0.669zM16 3c-7.18 0-13 5.82-13 13s5.82 13 13 13 13-5.82 13-13-5.82-13-13-13zM16 26c-5.522 0-10-4.478-10-10 0-5.523 4.478-10 10-10 5.523 0 10 4.477 10 10 0 5.522-4.477 10-10 10z"></path>
                    </svg>
                </span>
                <span class="hierarchy__item__icon hierarchy__item__circle-minus" *ngIf="node.checked && !node.allSelected">
                    <svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="24" height="28" viewBox="0 0 24 28">
                        <title>minus-circle</title>
                        <path d="M19 15v-2c0-0.547-0.453-1-1-1h-12c-0.547 0-1 0.453-1 1v2c0 0.547 0.453 1 1 1h12c0.547 0 1-0.453 1-1zM24 14c0 6.625-5.375 12-12 12s-12-5.375-12-12 5.375-12 12-12 12 5.375 12 12z"></path>
                    </svg>
                </span>
                {{node.name}}
            </label>
                
        </div>
        <ul *ngIf="node.children" class="hierarchy" [style.display]="!node.expanded ? 'none' : 'block'">
            <ng-container *ngTemplateOutlet="hierarchyNode; context: {$implicit: node.children, level: 'second', parent: node}"></ng-container>
        </ul>
    </li>
</ng-template>

层次结构.component.scss

* {
    &,
    &:before,
    &:after {
    box-sizing: border-box;
    margin: 0px;
    padding: 0px;
    }
}
.flex {  
    display: flex;
}

.flex-col {  
    display: flex;
    flex-direction: column;
}

.flex-inline {  
    display: inline-flex;
}

.flex-inline-col {  
    display: inline-flex;
    flex-direction: column;
}

.absCenter {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
}



.dropdown {
    width: 300px;
    position: relative;

    &__btn {
        background-color: #fff;
        color: #000;
        box-shadow: 4px 4px 5px rgba(0, 0, 0, 0.4);
        height: 35px;
        padding: 10px;
        font-size: 14px;
        text-align: center;
        text-transform: UPPERCASE;
        cursor: pointer;

        &:after {
            content: "";
            width: 0; height: 0; position: absolute; right: 5px; top:45%;
            border-top: 5px solid #000;
            border-left: 5px solid transparent;
            border-right: 5px solid transparent;
        }

        &:active {
            transform: translateY(2px);
            box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.2)
        }
    }

    &__content {
        display: none;
        position: absolute;
        top: 38px;
        left: 0px;
        width: 100%;
        z-index: 99;
        background: #fff;
        box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.4);
        max-height: 300px;
        overflow: hidden;
    }

    &__search {
        width: 100%;
        height: 30px;
        border-bottom: 1px solid #e0e0e0;
    }

    &__hierarchy {
        list-style: none;
        max-height: 270px;
        overflow: auto;

        &__list {
            margin-top: 5px;
        }
    }
}

.toggle-drop-down {
    display: block;
}

svg {
    width: 20px !important;
    height: 20px !important;
}

.hierarchy {
    margin-left: 10px;

    &__item {
        padding: 5px 0px;

        &__icon {
            width: 20px;
            margin-right: 10px;
        }

        &__label {
            padding-left: 10px;
        }

        &__checkbox {
            align-self: center;
            display: none;
        }
    }
}

.last-children {
    margin-left: 35px;
}

层次结构.model.ts

mockData 用于测试目的。应用程序运行后,删除此模拟数据。

export class Node {
    constructor(
        public id: string,
        public name: string,
        public children?: Array<Node>,
        public allSelected?: boolean,
        public expanded?: boolean,
        public checked?: boolean,
        public parentRef?: Node,
    ) { }
}

export const mockData: Array<Node> = new Array<Node>(
    new Node('1000', 'First level 1', [
        new Node('1100', 'Second level 11', [
            new Node('1110', 'Third level 111', [
                new Node('1111', 'Fourth level 1111'),
                new Node('1112', 'Fourth level 1112'),
                new Node('1113', 'Fourth level 1113'),
                new Node('1114', 'Fourth level 1114')
            ]),
            new Node('1120', 'Third level 112', [
                new Node('1121', 'Fourth level 1121'),
                new Node('1122', 'Fourth level 1122'),
                new Node('1123', 'Fourth level 1123'),
                new Node('1124', 'Fourth level 1124')
            ])
        ]),
        new Node('1200', 'Second level 12', [
            new Node('1210', 'Third level 121', [
                new Node('1211', 'Fourth level 1211'),
                new Node('1212', 'Fourth level 1212'),
                new Node('1213', 'Fourth level 1213'),
                new Node('1214', 'Fourth level 1214')
            ]),
            new Node('1220', 'Third level 122', [
                new Node('1221', 'Fourth level 1221'),
                new Node('1222', 'Fourth level 1222'),
                new Node('1223', 'Fourth level 1223'),
                new Node('1224', 'Fourth level 1224')
            ])
        ])
    ]),
    new Node('2000', 'First level 2', [
        new Node('2100', 'Second level 21', [
            new Node('2110', 'Third level 211', [
                new Node('2111', 'Fourth level 2111'),
                new Node('2112', 'Fourth level 2112'),
                new Node('2113', 'Fourth level 2113'),
                new Node('2114', 'Fourth level 2114')
            ]),
            new Node('2120', 'Third level 212', [
                new Node('2121', 'Fourth level 2121'),
                new Node('2122', 'Fourth level 2122'),
                new Node('2123', 'Fourth level 2123'),
                new Node('2124', 'Fourth level 2124')
            ])
        ]),
        new Node('2200', 'Second level 22', [
            new Node('2210', 'Third level 221', [
                new Node('2211', 'Fourth level 2211'),
                new Node('2212', 'Fourth level 2212'),
                new Node('2213', 'Fourth level 2213'),
                new Node('2214', 'Fourth level 2214')
            ]),
            new Node('2220', 'Third level 222', [
                new Node('2221', 'Fourth level 2221'),
                new Node('2222', 'Fourth level 2222'),
                new Node('2223', 'Fourth level 2223'),
                new Node('2224', 'Fourth level 2224')
            ])
        ])
    ])
);

app.component.ts

import { Component } from '@angular/core';
import { Node, mockData } from './hierarchy/hierarchy.model';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  public hierarchyData: Array<Node>;
  public selectedNodeIds: Array<string> = [];
  public selectedIds: Array<string> = [];


  constructor() {
    this.hierarchyData = mockData;
  }

  public changedSelectedIds(ids: Array<string>) {
    this.selectedIds = ids;
  }
}

应用程序组件.html

<div class="container">
    <app-hierarchy name="Hierarchy" 
        [data]="hierarchyData" 
        [selectedNodeIds]="selectedNodeIds"
        (selectedIds)="changedSelectedIds($event)">
    </app-hierarchy>
</div>

输出

在此处输入图片说明

在此处输入图片说明

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

SAPUI5:如何创建控件层次结构?

来自分类Dev

Angular 2如何创建嵌套结构?

来自分类Dev

如何从层次结构创建嵌套列表

来自分类Dev

如何创建模型的层次结构?

来自分类Dev

如何从 JSON 创建 Tableview 层次结构?

来自分类Dev

使用NIB创建复杂的VC层次结构

来自分类Dev

如何在路由层次结构中的某个点“装载” Angular 2模块的路由

来自分类Dev

如何在SQLServer上使用FOR XML创建层次结构

来自分类Dev

如何在SQLServer上使用FOR XML创建层次结构

来自分类Dev

如何以元组为导数创建结构或层次结构?

来自分类Dev

使用 angular 创建视图结构

来自分类Dev

如何重复序列:r中的1,2,3,4,5,6,1,2,3,4,5,6,7,8,9,10,7,8,9,10

来自分类Dev

剑道:如何在TreeView中创建递归层次结构?

来自分类Dev

如何从列中的数据创建层次结构索引?

来自分类Dev

如何创建在Akka中表达层次结构的角色?

来自分类Dev

SQL Server:如何从表创建层次结构组合

来自分类Dev

如何从底部SQL Server创建层次结构路径

来自分类Dev

如何在matplotlib中创建层次结构标签

来自分类Dev

剑道:如何在TreeView中创建递归层次结构?

来自分类Dev

如何创建如下所示的UNIX组层次结构?

来自分类Dev

如何在ER图中创建角色层次结构?

来自分类Dev

如何从父子层次结构表创建查询

来自分类Dev

如何在 Haskell 中创建树层次结构?

来自分类Dev

Angular2嵌套组件和模板层次结构

来自分类Dev

Angular 2进样器层次结构和NgModule

来自分类Dev

是否可以使用UIMA创建注释的层次结构?

来自分类Dev

是否可以使用UIMA创建注释的层次结构?

来自分类Dev

使用自动布局以编程方式创建视图层次结构

来自分类Dev

无法使用LUIS API创建实体层次结构

Related 相关文章

  1. 1

    SAPUI5:如何创建控件层次结构?

  2. 2

    Angular 2如何创建嵌套结构?

  3. 3

    如何从层次结构创建嵌套列表

  4. 4

    如何创建模型的层次结构?

  5. 5

    如何从 JSON 创建 Tableview 层次结构?

  6. 6

    使用NIB创建复杂的VC层次结构

  7. 7

    如何在路由层次结构中的某个点“装载” Angular 2模块的路由

  8. 8

    如何在SQLServer上使用FOR XML创建层次结构

  9. 9

    如何在SQLServer上使用FOR XML创建层次结构

  10. 10

    如何以元组为导数创建结构或层次结构?

  11. 11

    使用 angular 创建视图结构

  12. 12

    如何重复序列:r中的1,2,3,4,5,6,1,2,3,4,5,6,7,8,9,10,7,8,9,10

  13. 13

    剑道:如何在TreeView中创建递归层次结构?

  14. 14

    如何从列中的数据创建层次结构索引?

  15. 15

    如何创建在Akka中表达层次结构的角色?

  16. 16

    SQL Server:如何从表创建层次结构组合

  17. 17

    如何从底部SQL Server创建层次结构路径

  18. 18

    如何在matplotlib中创建层次结构标签

  19. 19

    剑道:如何在TreeView中创建递归层次结构?

  20. 20

    如何创建如下所示的UNIX组层次结构?

  21. 21

    如何在ER图中创建角色层次结构?

  22. 22

    如何从父子层次结构表创建查询

  23. 23

    如何在 Haskell 中创建树层次结构?

  24. 24

    Angular2嵌套组件和模板层次结构

  25. 25

    Angular 2进样器层次结构和NgModule

  26. 26

    是否可以使用UIMA创建注释的层次结构?

  27. 27

    是否可以使用UIMA创建注释的层次结构?

  28. 28

    使用自动布局以编程方式创建视图层次结构

  29. 29

    无法使用LUIS API创建实体层次结构

热门标签

归档