Angularで階層構造の表を開発(Treetable)

こんにちは。今回は表題の内容を解説します。
Angular MaterialMat-tableMat-treeを組み合わせれば実現可能ですが、初級者には難しく、コードが複雑になります。そこで、簡単に階層型の表を生成可能なOSS:Treetableを利用します。

Treetable

Treetableの導入手順

1. install

  • 以下を実行

    1
    npm i ng-material-treetable --save
  • Angular Materialパッケージがinstallされていることを確認

    • 既に入れていればスルー
      1
      npm i @angular/material @angular/cdk @angular/animations --save

2. app.module.tsでModuleをimport

  • src/app/app.module.tsを改修
    • TreetableModuleをimport
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      import { TreetableModule } from 'ng-material-treetable';

      @NgModule({
      ...
      imports: [
      ...
      TreetableModule
      ],
      ...
      })
      export class AppModule { }

3. Component側で使用

3.1. HTML

  • sample.component.htmlを改修
    • treetable要素を加えるだけでOKです
      1
      <treetable [tree]="yourTreeDataStructure"></treetable>

      3.2. TS

  • sample.component.ts
    • データソースとinterface(データの型)を規定します
      • GET等で外部APIからデータを持ってくる場合は、べた書きしているデータ部分を返り値に差し替えてください
      • データ構造は自由です。無くてもOK
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
import { Component, OnInit } from '@angular/core';

// 追加
import { Node, Options } from 'ng-material-treetable';


@Component({
selector: 'app-tree-table',
templateUrl: './tree-table.component.html',
styleUrls: ['./tree-table.component.scss']
})
export class TreeTableComponent implements OnInit {

// データソースを定義
// 省略部分はJSONデータ 表2のデータソース class内の先頭に必要であった
arrayOfNodesTree: Node<Task>[] = [
{
value: {
name: 'Tasks for Sprint 1',
completed: true,
owner: 'Marco'
},
children: [
{
value: {
name: 'Complete feature #123',
completed: true,
owner: 'Marco'
},
children: []
},
{
value: {
name: 'Update documentation',
completed: true,
owner: 'Jane'
},
children: [
{
value: {
name: 'Proofread documentation',
completed: true,
owner: 'Bob'
},
children: []
}
]
}
]
},
{
value: {
name: 'Tasks for Sprint 2',
completed: false,
owner: 'Erika',
},
children: [
{
value: {
name: 'Fix bug #567',
completed: false,
owner: 'Marco'
},
children: []
},
{
value: {
name: 'Speak with clients',
completed: true,
owner: 'James'
},
children: []
}
]
}
];

constructor() { }

ngOnInit() {
}

}

// 表のデータ構造の定義
export interface Task {
name: string;
completed: boolean;
owner: string;
}

4. Optionを設定

  • sample.component.tsの改修
    1
    2
    // 追加の必要有
    import { Node, Options } from 'ng-material-treetable';
  • sample.component.htmlの改修
    • [options]による指定で適用できます
      1
      2
      3
      4
      <treetable
      [tree]="yourTreeDataStructure"
      [options]="yourOptions">
      </treetable>

Eventの設定

  • sample.component.html
    1
    2
    3
    4
    5
    <treetable
    [tree]="yourTreeDataStructure"
    (nodeClicked)="logToggledNode($event)">
    <!--Clickで開閉-->
    </treetable>
  • sample.component.ts
    • nodeClickedで動くメソッドを定義
      1
      2
      3
      logToggledNode(node: Node<SomeNodeType>): void {
      console.log(node);
      }

 以上で階層型の表が完成しました。後は、データソースを直接編集するか、外部から取得したデータに差し替えるだけです。手順の解説は以上です。WEB AP開発の初級者は台帳APでも試しに作ってみると良いかもしれません。(Excelはやめましょう)
おまけとして、StackBlitzに挙がっていたサンプルソースの解説も置いておきます。

サンプルソースの解説

  • StackBlitz

    • 以下の書き方で今回の要件は満たせそう
      1
      arrayOfNodesTree: Node<Task>[] = 外部からGETしてきたデータ
  • app.component.ts

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    import { Component } from '@angular/core';

    // 追加の必要有
    import { Node, Options } from 'ng-material-treetable';

    @Component({
    selector: 'my-app',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
    })
    export class AppComponent {

    // 表1のOption
    treeOptions: Options<Report> = {
    capitalisedHeader: true,
    customColumnOrder: [// 列名を定義?
    'owner', 'name', 'backup', 'protected'
    ]
    };

    // 省略部分はJSONデータ 表1のデータソース
    singleRootTree: Node<Report> = {
    value: {
    name: 'Reports',
    owner: 'Eric',
    protected: true,
    backup: true
    },
    children: [
    {
    中略
    }
    ]
    };

    // 省略部分はJSONデータ 表2のデータソース
    arrayOfNodesTree: Node<Task>[] = [
    {中略
    }
    ]

    logNode(node: Node<Report>) {
    console.log(node);
    }

    }

    // 表のデータ型 列の要素を定義

    // 表1
    export interface Report {
    name: string;
    owner: string;
    protected: boolean;
    backup: boolean;
    }

    // 表2
    export interface Task {
    name: string;
    completed: boolean;
    owner: string;
    }
  • 次にHTML側を確認

    • かなりシンプルに書ける
      • treetable要素の中にデータソースとして定義したものを指定するだけ
        1
        2
        3
        4
        5
        <treetable
        [tree]="TS側で定めたデータソース名"
        (nodeClicked)="logNode($event)"> // Clickで開閉
        >
        </treetable>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 表1
<h2>Tree as Single Root Node</h2>
<treetable
[tree]="singleRootTree"
[options]="treeOptions"
(nodeClicked)="logNode($event)">
</treetable>

// 表2
<h2>Tree as Array of Nodes</h2>
<treetable
[tree]="arrayOfNodesTree" // tsでデータソースを定めたやつ
(nodeClicked)="logNode($event)">
</treetable>

自分でサンプルを開発した際のメモ

  • tree-table Componentを新たに生成

    1
    \src\app> ng g component tree-table
  • 上の階層のComponentでtree-tableを参照するように変更

    • serveで画面への反映を確認。問題無し
      1
      2
      3
      4
      5
      6
      7
      8
      9
      </mat-card-header>
      <mat-card-content>
      <div>

      <app-tree-table></app-tree-table>
      <!--tree tableコンポーネントを挿入---->

      </div>
      </mat-card-content>

サンプルデータで表を出す

  • tree-tableコンポーネントを改修

  • HTMLの改修

    1
    2
    3
    4
    <treetable
    [tree]="arrayOfNodesTree"
    (nodeClicked)="logNode($event)">
    </treetable>
  • tsの改修

    • import, データソース, interfaceを定義
    • 列を減らしてみる
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import { Node, Options } from 'ng-material-treetable';

// 省略部分はJSONデータ 表2のデータソース
arrayOfNodesTree: Node<Task>[] = [
{
value: {
name: 'Tasks for Sprint 1',
completed: true,
owner: 'Marco'
},
children: [
{
value: {
name: 'Complete feature #123',
completed: true,
owner: 'Marco'
},
children: []
},
{
value: {
name: 'Update documentation',
completed: true,
owner: 'Jane'
},
children: [
{
value: {
name: 'Proofread documentation',
completed: true,
owner: 'Bob'
},
children: []
}
]
}
]
},
{
value: {
name: 'Tasks for Sprint 2',
completed: false,
owner: 'Erika',
},
children: [
{
value: {
name: 'Fix bug #567',
completed: false,
owner: 'Marco'
},
children: []
},
{
value: {
name: 'Speak with clients',
completed: true,
owner: 'James'
},
children: []
}
]
}
]

logNode(node: Node<Report>) {
console.log(node);
}

}

// 表のデータ構造を決定
export interface Task {
name: string;
completed: boolean;
owner: string;
}
  • AP画面への反映を確認
    1
    ng serve --open
  • 以下のように表示された
  • エラーが発生

    • class内で初めにデータの定義が必要
    • 順番を入れ替えればOK
  • 最終的なtsファイル

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    import { Component, OnInit } from '@angular/core';

    // 追加
    import { Node, Options } from 'ng-material-treetable';


    @Component({
    selector: 'app-tree-table',
    templateUrl: './tree-table.component.html',
    styleUrls: ['./tree-table.component.scss']
    })
    export class TreeTableComponent implements OnInit {

    // データソースを定義
    // 省略部分はJSONデータ 表2のデータソース class内の先頭に必要であった
    arrayOfNodesTree: Node<Task>[] = [
    {
    value: {
    name: 'Tasks for Sprint 1',
    completed: true,
    owner: 'Marco'
    },
    children: [
    {
    value: {
    name: 'Complete feature #123',
    completed: true,
    owner: 'Marco'
    },
    children: []
    },
    {
    value: {
    name: 'Update documentation',
    completed: true,
    owner: 'Jane'
    },
    children: [
    {
    value: {
    name: 'Proofread documentation',
    completed: true,
    owner: 'Bob'
    },
    children: []
    }
    ]
    }
    ]
    },
    {
    value: {
    name: 'Tasks for Sprint 2',
    completed: false,
    owner: 'Erika',
    },
    children: [
    {
    value: {
    name: 'Fix bug #567',
    completed: false,
    owner: 'Marco'
    },
    children: []
    },
    {
    value: {
    name: 'Speak with clients',
    completed: true,
    owner: 'James'
    },
    children: []
    }
    ]
    }
    ];

    constructor() { }

    ngOnInit() {
    }

    }

    // 表のデータ構造の定義
    export interface Task {
    name: string;
    completed: boolean;
    owner: string;
    }
  • 参考ページ

  • Mat-treeとMat-tableを組み合わせて開発する場合の参考

@EventEmitter @Input @Output @ViewChild ACM AMP API Gateway AR AR.js AR.js Studio AWS AWS Amplify AWS Budgets AWS Cost Explorer AWS SDK for JavaScript AddThis Adobe XD Alexa Amazon CloudWatch Amazon Honycode Amazon SNS Android Angular Angular Material AngularFire AppSync Augury C CDN CI/CD Cloud Craft Cloud9 CloudFormation CloudFront CloudTrail Cognito Cost Anomaly Detection Cubase ai Cubasis LE DTM Disqus DynamoDB Elgato HD 60S Firebase Firebase Hosting Former2 Github Github Actions Github.com GithubEnterprise GithubPages Google Chrome Google Cloud Shell GraphQL Hexo Hosting IAM Ionic JSON JavaScript LadioCast Logging LowCode MFA MS Authentication MacBook Pro 16 Mind Node NETDUETTO Netflix Party Netlify Network NoCode Observable PO PdM Promise RPA ReactiveForm Recognition Route53 S3 SAM(Serverless Application Model) SAR SSL SYNCROOM Schematics ScrumInc Serverless Service Siri Sitemap Spark AR Steinberg UR44C Teams Touch Cast Studio Treetable TypeScript UI UI Bakery WAF WAFv2 WEB Page Dev WEB会議 WebAR WebSocketAPI Webhook Windows Power Automate Wireshark aot async/await aws config cloud9 display.land draw.io e2e test filter() forkJoin() google search console hexo-generator-amp iOS iPad Pro iPhone icarus map() mat input mat tree mat-checkbox mat-input mat-selection-list mmhmm ngFor plantUML popIn Aladdin2 then() vscode ”global is not defined” らくがきAR アジャイル アジャイル開発 クロスプラットフォーム ショートカット スクラム スクラム開発 テレワーク ファイル操作 ブラウザ型IDE プロダクトオーナー プロダクトマネージャー プロトタイピング リモートセッション 共同開発 双方向データバインディング 待ち合わせ処理 認定スクラムマスター 静的WEB Hosting 静的WEBサイトHosting
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×