5.0.0 • Published 5 years ago

@rign/angular2-tree v5.0.0

Weekly downloads
5
License
MIT
Repository
github
Last release
5 years ago

Aangular Tree Component

Simple component to display tree structure

npm (scoped) Build Status npm npm

Installation

npm i @rign/angular2-tree --save

It also require to install dependencies:

  • @angular/animations
  • @angular/cdk
  • @angular/common
  • @angular/core
  • @angular/forms
  • @angular/http
  • @ngrx/core
  • @ngrx/effects
  • @ngrx/store
  • @ngrx/store-devtools
  • angular2-uuid
  • bootstrap
  • core-js
  • font-awesome
  • lodash.isequal
  • ng2-dnd
  • ngx-contextmenu
  • rxjs
  • zone.js

You can install them using below command:

npm i @angular/cdk @angular/common @angular/core @angular/forms @angular/http @ngrx/core @ngrx/effects @ngrx/store angular2-uuid bootstrap core-js font-awesome lodash.isequal ng2-dnd ngx-contextmenu rxjs zone.js --save 

Usage

First you have to create your own loader service

@Injectable()
export class AppNodeService extends NodeService {
  public get treeId(): string {
    return 'tree3';
  }
  
  protected apiConfig = {
    addUrl: '/api/nodes',
    getUrl: '/api/nodes',
    updateUrl: '/api/nodes',
    removeUrl: '/api/nodes',
  }
}

and use it to load/save/delete/etc. your node data. Or you can extend and rewrite all methods of that service to store your data wherever you want. See example localStorage.service.ts

Include TreeModule in your application module and create Store with empty state and initialize Effects. Do not forget to pass yours AppNodesService as a parameter of TreeModule.

import {TreeModule} from '@rign/angular2-tree';

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    TreeModule.forRoot(AppNodeService),
    EffectsModule.forRoot([]),
    StoreModule.forRoot({})
  ]
})

You need also init animations module, because Tree needs it to animate expanding and collapsing node.

@NgModule({
  declarations: [
    ...
  ],
  imports: [
    ...
    BrowserAnimationsModule,
    TreeModule.forRoot()
  ]
})

In any html file put

<ri-tree [treeModel]="treeModel"></ri-tree>

In component where you create tree, you should create TreeModel passing configuration and AppNodeService.

export class MyTreeComponent implements OnInit {
  public folders: Observable<ITreeData>;

  public contextMenu: IContextMenu[] = [];

  public treeConfiguration: IConfiguration = {
    showAddButton: true,
    disableMoveNodes: false,
    treeId: 'tree3',
    dragZone: 'tree3',
    dropZone: ['tree3'],
    isAnimation: true     // add animation to action "expand" and "collapse"
  };

  public treeModel: TreeModel;


  public constructor(private treeInitializerService: TreeInitializerService,
                     private appNodeService: AppNodeService) {
  }

  public ngOnInit(): void {
    const nodes: IOuterNode[] = JSON.parse(localStorage.getItem('treeOne')) || [];

    this.treeModel = this.treeInitializerService.init(this.treeConfiguration, this.appNodeService, nodes);
  }
}

If function init has got third parameter - array of nodes, then the tree will be marked as fully loaded. It will not use load API function to get new subnodes it will use only passed nodes.

CSS Styles

To load default CSS styles and makes our tree looks nice you have to add 2 CSS files to your angular-cli.json file:

...
"styles": [
  "../node_modules/bootstrap/dist/css/bootstrap.css",
  "../node_modules/font-awesome/css/font-awesome.css",
  "styles.css"
],

Create own item template

Also you can use your own template to display items. You can do that when you extend ItemComponent

@Component({
  selector: 'new-tree-item',
  templateUrl: './newItem.component.html',
  styleUrls: ['./newItem.component.scss']
})
export class NewItemComponent extends ItemComponent {

}

and newItem.component.html

<div class="tree-item row"
     [ngClass]="{'tree-item-selected': isSelected}"
     riDroppable
     riDraggable
     [dragZone]="treeModel.configuration.dragZone"
     [dropConfig]="{dropAllowedCssClass: 'drop-enabled', dropZone: treeModel.configuration.dropZone}"
     [data]="node"
     id="node-{{node-id}}"
>
  <div class="col-sm-8">
    <i *ngIf="!isExpanded" (click)="expand()" class="fa fa-plus pointer"></i>
    <i *ngIf="isExpanded" (click)="collapse()" class="fa fa-minus pointer"></i>
    <span *ngIf="!isEditMode" class="tree-item-name" (click)="onSelect()">{{node.name}}</span>
    <form name="form">
      <input #inputElement type="text" class="form-control" *ngIf="isEditMode" [formControl]="nameField"
             name="name" (keydown)="onChange($event)" (blur)="onBlur($event)"/>
    </form>
  </div>
  <div class="col-sm-4 text-right">
      <span class="btn-group btn-group-sm">
        <button class="btn btn-primary" (click)="onEdit($event)" [disabled]="isEditMode">
          <i class="fa fa-edit"></i>
        </button>
        <button class="btn btn-danger" (click)="onDelete()" [disabled]="isEditMode">
          <i class="fa fa-trash"></i>
        </button>
      </span>
  </div>
</div>
<div class="tree" *ngIf="isExpanded" [@expand]>
  <ri-tree-item *ngFor="let child of children$ | async" [node]="child; trackBy: trackByFn"
                [treeModel]="treeModel"
                [isExpanded]="treeModel.isExpanded(child)"
                [isSelected]="treeModel.isSelected(child)"
                [contextMenu]="contextMenu"></ri-tree-item>
</div>

Then when you create tree component in your application use such construction

<rign-tree [treeModel]="treeModel">
  <new-tree-item *ngFor="let node of treeModel.getRootNodes() | async; trackBy: trackByFn" 
                  [node]="node" 
                  [treeModel]="treeModel" 
                  [isSelected]="treeModel.isSelected(node)"
                  [isExpanded]="treeModel.isExpanded(node)"
                  [contextMenu]="contextMenu"></new-tree-item>
</rign-tree>

and that is all. Please see Demo where is such example.

Open initial path

If you would like to open some path at the begin you can do that invoking such method after creating TreeModel.

 this.treeModel.initPath([
   // list of node ids sorted by level of node (grandparent id, parent id, child id)
 ]);
  

Display parents path

From version 3.0.1 there is possibility to display current selected node path. To do that place in your component html file such code:

<ri-tree-parents-list [treeModel]="treeModel"></ri-tree-parents-list>

The treeModel value is the same object that is used in ri-tree.

Events(Actions)

Using ngrx/store you can listen on below actions and do whatever you want:

TreeActionTypes.TREE_SAVE_NODE
TreeActionTypes.TREE_SAVE_NODE_ERROR
TreeActionTypes.TREE_SAVE_NODE_SUCCESS
TreeActionTypes.TREE_DELETE_NODE
TreeActionTypes.TREE_DELETE_NODE_ERROR
TreeActionTypes.TREE_DELETE_NODE_SUCCESS
TreeActionTypes.TREE_EDIT_NODE_START
TreeActionTypes.TREE_EXPAND_NODE
TreeActionTypes.TREE_LOAD
TreeActionTypes.TREE_LOAD_ERROR
TreeActionTypes.TREE_LOAD_SUCCESS
TreeActionTypes.TREE_LOAD_PATH
TreeActionTypes.TREE_MOVE_NODE
TreeActionTypes.TREE_MOVE_NODE_ERROR
TreeActionTypes.TREE_MOVE_NODE_SUCCESS
TreeActionTypes.TREE_REGISTER
TreeActionTypes.TREE_SET_ALL_NODES
TreeActionTypes.TREE_SELECT_NODE

Translation

From version 5.0.0 translation dependency is removed from @rign/angular2-tree. Now you have to create service which implements ITreeTranslation interface:

import {ITreeTranslations} from '@rign/angular2-tree';

export class TreeTranslationService implements ITreeTranslations {
  readonly RI_TREE_LBL_ADD_NODE = 'Add data';
  readonly RI_TREE_LBL_EDIT_NODE = 'Edit data';
  readonly RI_TREE_LBL_REMOVE_NODE = 'Delete data';
  readonly RI_TREE_LBL_DROP_ZONE = 'Drop here to move data to root level';
}

and set is as provider in module which use TreeModule

providers: [
    TreeOneNodeService,
    {provide: TREE_TRANSLATION_TOKEN, useClass: TreeTranslationService},
]

In such case you can use your own translation module and its implementation or even if you don't use translations in your app, you don't have to import additional dependency.

Drop elements on tree node

Now you have new possibilities to move different elements to the tree (files or other data). To do that, you have to use riDraggable directive in following way

<div ri-draggable [dragZone]="treeModel.configuration.dragZone" [data]="your_data" [sourceType]="'YOUR_SOURCE_TYPE'">Drag element</div>  

where:

  • your_data - is any object
  • YOUR_SOURCE_TYPE - is any type of string which allow you to filter drop effect

Then you have to create @Effects similar to that one in _treeEffects.service_or create only Observable and subscribe to it.

@Effect() move$ = this.actions$
  .pipe(
    ofType(TreeActionTypes.TREE_MOVE_NODE),
    filter((action: ITreeAction) => {
      return action.payload.sourceOfDroppedData === DragAndDrop.DROP_DATA_TYPE;
    }) 
  )
  ...
  

but you have to replace

ofType(TreeActionTypes.TREE_MOVE_NODE)

to

ofType('YOUR_SOURCE_TYPE')
  

At the end do not forget to add this effects to your app.

Changes

v5.0.0

  • remove translation module
  • add ITreeTranslation interface and TREE_TRANSLATION_TOKEN

v4.1.0

  • update to Angular 8

v4.0.0

  • update to Angular 7
  • switch from ng2-translate to ngx-translate
  • replace LESS to SCSS
  • move to new repository
  • remove deprecated code

v3.1.2

  • fix Item template error
  • update bootstrap to 4.1.3

v3.1.0

  • change tree model initialize and injecting NodeService
  • add NestJS server with new TreeTwoNodeBackendService angular service to show how Tree works with real backend (details in Demo section)
  • actions and reducer
    • change events from TreeActionService to TreeActionTypes (the first one will be removed in 4.0.0)
    • rewrite actions from one class to many simpler classes
    • create one type TreeAction which cover all tree actions
  • rewrite TreeItemComponent - improved performance and reduce code
    • move information about expanded nodes from TreeItemComponent to store, these cause that isExpanded is now @Input() property for TreeItemComponent
    • TreeItemComponent has new @Input() property isSelected
    • small changes in expand animation
  • fix issue - when add new node parent node was expanded but not loaded

v3.0.2

  • small fixes with interfaces
  • fix export CSS styles

v3.0.1

  • change the way of injecting NodeService provider
  • save in store: tree root nodes list, tree configuration and selected node
  • display current selected node parents path with navigation
  • add possibility to open path of the tree

v2.3.0

  • fix problem with building tree component in AOT
  • fix few small issues

v2.2.0

  • add forRoot static method
  • change translation module to ng2-translate
  • upgrade angular to verison ^5.0.0
  • upgrade @ngrx/store to version ^4.1.0 (use forFeature to init store and effects)
  • rename selector ri-tree

v2.1.1

  • fix bug with adding new node to root element

v2.1.0

  • add translation module
  • drop elements on tree nodes
  • update and lock of some npm package versions
  • add possibility to animate action collapse and expand nodes of tree, using in configuration property isAnimation: true

v2.0.1

v2.0.0

  • use ngrx/store to store data
  • use actions and effects instead of events
  • add TravisCI configuration
  • remove backend example, move all functionality of demo to local storage

v1.0.0

  • use ngrx/store
  • remove events ITreeItemEvents - use Actions and Effects
  • remove NodeModel
  • simplify using tree

v0.8.1

  • fix package.json

v0.8.0

  • allow to create own template for tree item (if not specify it use default) - look in demo
  • input option disableContextMenu to disable context menu (default: false)
  • update Demo - add alternative view of tree

v0.7.0

  • remove API config service (see section Usage)

v0.6.2

  • change name FolderService to NodeService
  • change params names from dirId to nodeId
  • now you can use in your API paths parameter {nodeId} which will be replaced on nodeId

v0.6.1

  • expose ConfigService - it allow override urls for create, edit, and delete folder

v0.6.0

  • upgrade angular/cli to version beta.32.3
  • fix demo

v0.5.0

  • primary version with all features described below.

Demo

Working demo with local storage you can find here. To run Demo locally clone this repository and run

ng start --project=tree-example

License

Licensed under MIT.

5.0.0

5 years ago

4.1.0

5 years ago

4.0.0

5 years ago

3.1.2

6 years ago

3.1.1

6 years ago

3.1.0

6 years ago

3.0.2

6 years ago

3.0.1

6 years ago

3.0.0

6 years ago

2.3.0

6 years ago

2.3.0-rc1

6 years ago

2.2.0

6 years ago

2.1.1

7 years ago

2.1.0

7 years ago

2.0.1

7 years ago

2.0.0

7 years ago

0.8.1

7 years ago

0.8.0

7 years ago

0.7.0

7 years ago

0.6.2

7 years ago

0.6.1

7 years ago

0.6.0

7 years ago

0.5.0

7 years ago

0.4.0

7 years ago