ng2-drag-drop-tree: Search And Node Deletion Features
No post for many days since I have been travelling to Ecuador and Peru, my bad :s.
Let's add some new simple features in ng2-drag-drop-tree, this week: Searching and Deleting.
Searching
Let's add a directive so users can search for a specific text. If you have already worked with Angular 1, you are going to tell me "Well we can just use filter for that!". And yes you are right. However the Angular team decided that filter and orderBy are not great for performances (impure = more cycles) and not minification-friendly so they got tired of people complaining about that and took them out of Angular 2 core.
So let's create a custom filter!
We have a textfield in our template that will trigger the filter function on change. This function only uses TreeManager saying "The text to filter has this value now!".
import {Component} from '@angular/core';
import {TreeManager} from '../ng2-drag-drop-tree';
@Component({ selector: 'tree-search-textfield',
template:`<input type='text' [(ngModel)]='val' (ngModelChange)='filter(val)'>`})
export class TreeSearchTextField{
constructor(private treeManager:TreeManager) {}
filter(value){
this.treeManager.setFilteredText(value);
}
}
We then export the directive in our ng2-drag-drop-tree main file:
export * from "./tree-search-textfield/tree-search-textfield.directive";
Now let's create the pipe that we will use for our nodes.
For now we just create an impure pipe that is not awesome performance wise but that easily detects every changes.
The isBlank function handles the case when there is no text. If there is a specific text in the textfield, we ONLY return the nodes that contain this string.
import {Pipe, PipeTransform } from '@angular/core';
import {TreeManager} from '../services/tree-manager';
@Pipe({name: 'nodeSearch',pure:false})
export class NodeSearch implements PipeTransform{
constructor(private treeManager:TreeManager){
}
isBlank(obj: any): boolean {
return obj === undefined || obj === null;
}
transform(value){
var filteredText = this.treeManager.getFilteredText()
if (this.isBlank(filteredText)) { return value}
else {
return value.filter((node) => node.text.indexOf(filteredText) > -1);
}
}
}
Then we use our node-search pipe on the loop in tree-node.html:
*ngFor="#child of children | nodeSearch"
We export the newly created pipe in the main ng2-drag-drop-tree file.
export * from "./pipes/node-search";
We add the directive in the template where the nodes are:
<tree-search-textfield></tree-search-textfield>
<tree-node [children]="[{text:'First node', subNodes:[],expanded:false},
{text:'Fourth node', subNodes:[],expanded:false}]"></tree-node>
<tree-node [children]="[{text:'Second node', subNodes:[],expanded:false}]"></tree-node>
<tree-node [children]="[{text:'Third node', subNodes:[],expanded:false}]"></tree-node>
And finally in the main component :
import {TreeNode, TreeSearchTextField} from '../tree-component/ng2-drag-drop-tree';
@Component({
selector: 'home',
directives: [TreeNode, TreeSearchTextField]
}
And Voila! This is a very basic search, for a better filter it would require a transposition of the angular 1 filter, here: https://github.com/angular/angular.js/blob/master/src/ng/filter/filter.js
Node Deletion
Let's start by adding a very beautiful X mark and a deleteNode function in the "tree-node.html" file. We pass in this function the child of the object that we are looping through.
<div pDroppable="dd" (click)='toggle(child)'
(onDrop)='onDrop($event,child)' style='border:1px solid black'> {{child.text}}
<span (click)='deleteNode(child)'>X</span>
</div>
We have : the actual object (this) which is the parent and the child that we passed. All we need to do in tree-node.component is to splice like we did in the previous chapter.
deleteNode(node) {
this.children.splice(this.children.indexOf(node), 1);
}
And Voila a very easy node deletion feature done!
Conclusion
We recreated a custom basic filter because Angular 2 isn't delivered with it anymore (maybe we will be able to npm install ng2-filter in the future) and added a node deletion feature using 4 lines of code.
What's remaining now: changing the text of the nodes, handling different type of drag/drop actions, handling actions on multiple nodes and enabling CSS customisation.