feat: add tree view in chart of accounts component

Add tree view for GL accounts in chart of accounts component.
This commit is contained in:
Abhay Chawla
2018-08-02 01:18:03 +05:30
parent 6643e44afc
commit 6f6378aa0e
7 changed files with 294 additions and 3 deletions
@@ -80,6 +80,118 @@
<div class="container" *ngIf="viewGroup.value === 'treeView'">
TREE VIEW
<div class="m-b-20" fxLayout="row" fxLayoutAlign="end" fxLayoutGap="20px">
<button mat-raised-button (click)="nestedTreeControl.expandAll()"> <!-- Bug(angular-material): https://github.com/angular/material2/issues/12170 -->
Expand All
</button>
<button mat-raised-button (click)="nestedTreeControl.collapseAll()">
Collapse All
</button>
</div>
<div fxLayout="row" fxLayoutGap="4%" fxLayout.lt-md="column">
<div fxFlex="48%" *ngIf="glAccount">
<mat-card>
<mat-card-content>
<div fxLayout="row wrap" class="content">
<div fxFlex="50%" class="header">
Account Name
</div>
<div fxFlex="50%">
{{ glAccount.name }}
</div>
<div fxFlex="50%" class="header">
GL Code
</div>
<div fxFlex="50%">
{{ glAccount.glCode }}
</div>
<div fxFlex="50%" class="header">
Account Type
</div>
<div fxFlex="50%">
{{ glAccount.type }}
</div>
<div fxFlex="50%" class="header">
Account Usage
</div>
<div fxFlex="50%">
{{ glAccount.usage }}
</div>
<div fxFlex="50%" class="header">
Manual Entries Allowed
</div>
<div fxFlex="50%">
{{ glAccount.manualEntriesAllowed }}
</div>
<div fxFlex="50%" class="header">
Description
</div>
<div fxFlex="50%">
{{ glAccount.description }}
</div>
</div>
</mat-card-content>
</mat-card>
</div>
<div class="mat-elevation-z8" fxFlex>
<mat-tree [dataSource]="nestedTreeDataSource" [treeControl]="nestedTreeControl" class="gl-account-tree">
<mat-tree-node *matTreeNodeDef="let node" matTreeNodeToggle>
<li class="mat-tree-node">
<button mat-icon-button disabled></button>
<span (click)="viewGLAccountNode(node)">
<span *ngIf="node.glCode">{{ '(' + node.glCode + ')' }}</span>&nbsp;&nbsp;
{{ node.name }}
</span>
</li>
</mat-tree-node>
<mat-nested-tree-node *matTreeNodeDef="let node; when: hasNestedChild">
<li>
<div class="mat-tree-node">
<button mat-icon-button matTreeNodeToggle [attr.aria-label]="'toggle ' + node.name">
<mat-icon class="mat-icon-rtl-mirror">
{{ nestedTreeControl.isExpanded(node) ? 'expand_more' : 'chevron_right' }}
</mat-icon>
</button>
<span (click)="viewGLAccountNode(node)">
<span *ngIf="node.glCode">{{ '(' + node.glCode + ')' }}</span>&nbsp;&nbsp;
{{ node.name }}
</span>
</div>
<ul [class.gl-account-tree-invisible]="!nestedTreeControl.isExpanded(node)">
<ng-container matTreeNodeOutlet></ng-container>
</ul>
</li>
</mat-nested-tree-node>
</mat-tree>
</div>
</div>
</div>
@@ -2,6 +2,36 @@ table {
width: 100%;
}
.gl-account-tree-invisible {
display: none;
}
.gl-account-tree ul,
.gl-account-tree li {
margin-top: 0;
margin-bottom: 0;
list-style-type: none;
}
.gl-account-tree {
li {
span {
cursor: pointer;
}
}
}
.content {
div {
margin: 1rem 0;
word-wrap: break-word;
}
.header {
font-weight: 500;
}
}
.disabled {
color: red;
}
@@ -1,8 +1,14 @@
import { Component, ViewChild, OnInit, AfterViewInit } from '@angular/core';
import { MatPaginator, MatSort, MatTableDataSource } from '@angular/material';
import { MatPaginator, MatSort, MatTableDataSource, MatTreeNestedDataSource } from '@angular/material';
import { NestedTreeControl } from '@angular/cdk/tree';
import { FormControl } from '@angular/forms';
import { ActivatedRoute } from '@angular/router';
import { of } from 'rxjs';
import { GLAccountNode } from './gl-account-node.model';
import { GlAccountTreeService } from './gl-account-tree.service';
@Component({
selector: 'mifosx-chart-of-accounts',
templateUrl: './chart-of-accounts.component.html',
@@ -19,14 +25,32 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
@ViewChild(MatPaginator) paginator: MatPaginator;
@ViewChild(MatSort) sort: MatSort;
constructor(private route: ActivatedRoute) {
//
nestedTreeControl: NestedTreeControl<GLAccountNode>;
nestedTreeDataSource: MatTreeNestedDataSource<GLAccountNode>;
glAccount: GLAccountNode;
//
constructor(private glAccountTreeService: GlAccountTreeService,
private route: ActivatedRoute) {
this.route.data.subscribe((data: { glAccountData: any }) => {
this.glAccountData = data.glAccountData;
glAccountTreeService.initialize(this.glAccountData);
});
//
this.nestedTreeControl = new NestedTreeControl<GLAccountNode>(this._getChildren);
this.nestedTreeDataSource = new MatTreeNestedDataSource();
//
}
ngOnInit() {
this.tableDataSource = new MatTableDataSource(this.glAccountData);
//
this.glAccountTreeService.treeDataChange.subscribe((glAccountTreeData: any) => {
this.nestedTreeDataSource.data = glAccountTreeData;
this.nestedTreeControl.expand(this.nestedTreeDataSource.data[0]);
});
//
}
ngAfterViewInit() {
@@ -49,4 +73,18 @@ export class ChartOfAccountsComponent implements AfterViewInit, OnInit {
console.log(glAccount);
}
//
hasNestedChild = (_: number, node: GLAccountNode) => node.children.length;
viewGLAccountNode(glAccount: GLAccountNode) {
if (glAccount.glCode) {
this.glAccount = glAccount;
} else {
delete this.glAccount;
}
}
private _getChildren = (node: GLAccountNode) => of(node.children);
//
}
@@ -0,0 +1,23 @@
export class GLAccountNode {
children: GLAccountNode[];
name: string;
glCode: string;
type: string;
usage: string;
manualEntriesAllowed: boolean;
description: string;
constructor(name: string,
glCode: string = '',
type: string = '',
usage: string = '',
manualEntriesAllowed: boolean = false,
description: string = '') {
this.name = name;
this.glCode = glCode;
this.type = type;
this.usage = usage;
this.manualEntriesAllowed = manualEntriesAllowed;
this.description = description;
this.children = [];
}
}
@@ -0,0 +1,15 @@
import { TestBed, inject } from '@angular/core/testing';
import { GlAccountTreeService } from './gl-account-tree.service';
describe('GlAccountTreeService', () => {
beforeEach(() => {
TestBed.configureTestingModule({
providers: [GlAccountTreeService]
});
});
it('should be created', inject([GlAccountTreeService], (service: GlAccountTreeService) => {
expect(service).toBeTruthy();
}));
});
@@ -0,0 +1,70 @@
import { Injectable } from '@angular/core';
import { BehaviorSubject } from 'rxjs';
import { GLAccountNode } from './gl-account-node.model';
@Injectable({
providedIn: 'root'
})
export class GlAccountTreeService {
glAccountData: any;
treeDataChange = new BehaviorSubject<GLAccountNode[]>([]);
get treeData(): GLAccountNode[] { return this.treeDataChange.value; }
constructor() { }
initialize(glAccountData: any) {
const data = this.buildGLAccountTree(glAccountData);
this.treeDataChange.next(data);
}
buildGLAccountTree(glAccountData: any): GLAccountNode[] {
const glAccountTree: GLAccountNode[] = [];
glAccountTree.push(new GLAccountNode('GL ACCOUNTS'));
glAccountTree[0].children.push(new GLAccountNode('ASSET'));
glAccountTree[0].children.push(new GLAccountNode('EQUITY'));
glAccountTree[0].children.push(new GLAccountNode('EXPENSE'));
glAccountTree[0].children.push(new GLAccountNode('INCOME'));
glAccountTree[0].children.push(new GLAccountNode('LIABILITY'));
glAccountData.sort((glAccountOne: any, glAccountTwo: any) => {
if (!glAccountOne.parentId) {
glAccountOne.parentId = 0;
}
return glAccountOne.parentId - glAccountTwo.parentId;
});
const glAccounts: GLAccountNode[] = [];
for (const glAccount of glAccountData) {
glAccounts[glAccount.id] =
new GLAccountNode(glAccount.name, glAccount.glCode, glAccount.type.value, glAccount.usage.value, glAccount.manualEntriesAllowed, glAccount.description);
}
for (const glAccount of glAccountData) {
if (glAccount.parentId === 0) {
if (glAccount.type.value === 'ASSET') {
glAccountTree[0].children[0].children.push(glAccounts[glAccount.id]);
} else if (glAccount.type.value === 'EQUITY') {
glAccountTree[0].children[1].children.push(glAccounts[glAccount.id]);
} else if (glAccount.type.value === 'EXPENSE') {
glAccountTree[0].children[2].children.push(glAccounts[glAccount.id]);
} else if (glAccount.type.value === 'INCOME') {
glAccountTree[0].children[3].children.push(glAccounts[glAccount.id]);
} else if (glAccount.type.value === 'LIABILITY') {
glAccountTree[0].children[4].children.push(glAccounts[glAccount.id]);
}
} else {
glAccounts[glAccount.parentId].children.push(glAccounts[glAccount.id]);
}
}
return glAccountTree;
}
}
+3
View File
@@ -33,6 +33,7 @@ import { MatCheckboxModule,
MatTooltipModule,
MatSnackBarModule,
MatTableModule,
MatTreeModule,
MatSortModule,
MatPaginatorModule,
MatDividerModule,
@@ -98,6 +99,7 @@ import { AuthenticationInterceptor } from './authentication/authentication.inter
MatTooltipModule,
MatSnackBarModule,
MatTableModule,
MatTreeModule,
MatSortModule,
MatPaginatorModule,
MatDividerModule
@@ -143,6 +145,7 @@ import { AuthenticationInterceptor } from './authentication/authentication.inter
MatTooltipModule,
MatSnackBarModule,
MatTableModule,
MatTreeModule,
MatSortModule,
MatPaginatorModule,
MatDividerModule,