Last update on Wednesday, August 3rd 2016

ng2-drag-drop-tree: Everything about CSS and ngClass

Hi folks!

At the beginning I wanted to split adding default classes and configurable classes in two posts. Well **** it, let's do both at the same time! The mechanism that I use here is basically to allow YOU the user to pass an object with your classes (that will be passed to every sub-nodes) and if there is no property for a class, take the one by default.

The reason I don't just force the user to override the default classes is because it's more flexible. Instead of forcing the use of CSS, the user can use font-awesome, glyphicon, bootstrap, whatever classes.

I'm using FontAwesome for the default classes so head there if you have the same environment as mine (Angular 2 + Webpack) : https://github.com/gowravshekar/font-awesome-webpack

Let's start with the very important customClasses Object. It's an Input that you will set in your app (home.component, app.component, whereever-you-start-using-tree-node.component).

In tree-node.ts:

@Input('custom-classes') customClasses;

PS: Notice here that I use internal/external names.

And the CSS in the component:

@Component({
  ...
  styles:[require('./tree-node.css')]
  ...})

In your app:

  customClasses = {minusIcon:'icon-class'}

Here we only set one custom class.

We then set it in index.html so that it will leak into the project and reach our component:

<style>

.icon-class {
  background :url(assets/img/minus_button.png) no-repeat;
  width: 16px;
  height: 16px;
  float: right;
}
</style>

We then modify tree-node.html to pass customClasses to every sub-nodes:

 <tree-node [custom-classes]='customClasses' [children]='child.subNodes'></tree-node>

Nice! Now all our sub-nodes have the custom classes, let's use them now.

For now the user can modify 4 classes: minus, plus, chevron-down and chevron-right icons.

For the plus and minus icons, it's very simple, just using ngClass to use in priority the customClasses else if there is no property, use the default ones:

<i (click)='deleteNode(child)' [ngClass]="customClasses.minusIcon || 'fa fa-minus-circle pull-right'"></i>
<i (click)='addNewNode(child)' [ngClass]="customClasses.plusIcon || 'fa fa-plus-square pull-right'"></i>

Now for the chevrons, it becomes a bit more challenging. Using an object with ngClass to switch classes is very useful, example:

<i  class='fa' [ngClass]="{'fa-chevron-down': !isExpanded() || 'fa-chevron-right': isExpanded()" (click)='toggle(child)'></i>

BUT if we want to use variables for our classes in an object, ngClass doesn't understand what is going on! So unfortunately we can't use the fancy solution and need to separate this into 2 parts ...

<i *ngIf='hasChevronDown(child)' [ngClass]="customClasses.chevronDownIcon || 'fa fa-chevron-down'" (click)='toggle(child)'></i>
<i *ngIf='hasChevronRight(child)' [ngClass]="customClasses.chevronRightIcon || 'fa fa-chevron-right'" (click)='toggle(child)'></i>

We keep using the "Take the custom class or the default one" system and we display the chevron-down or chevron-right.

We finally add the trivial hasChrevronDown and hasChevronRight methods:a

hasChevronDown(child){
  return child.subNodes.length != 0 && child.expanded
}

hasChevronRight(child) {
  return child.subNodes.length != 0 && !child.expanded
}

Nothing fancy here, if there are no subNodes we don't display anything. We then check the state of the **expanded** property to see which icon to display.

And that's it. That's how you create in a component a system to allow the use of dynamic classes with a fallback to default classes.

You can have a look at the lib here and the demo here! I'll update them as soon as possible since at the moment I'm again between airports #digitalNomad.

Let's start an open source Angular 2 project: ng2-drag-drop-tree

ng2-drag-drop-tree: Search And Node Deletion Features

ng2-drag-drop-tree: Adding a new node and demo available!

Stay up to date


Join over 4000 other developers who already receive my tutorials and their source code out of the oven + other free stuff!