Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hierarchical Select in Angular 2

I'd like to render hierarchical selects. Each option in a select may have its own unique child selects. Ultimately, I want something like this.

I have a class called fieldSelect that represents a single select dropdown with an array of options:

export class fieldSelect {
    constructor(
        public options: Array<fieldOption>
    ){}
}

The fieldOption class represents a single option within a dropdown. It contains value, text, and children. The children portion is another select dropdown (making it hierarchical).

export class fieldOption {
    constructor(
        public text: string,
        public value: string,
        public children: Array<fieldOption>
    ) {}
}

Here's the Angular mockup on git.

like image 200
goodoldneon777 Avatar asked Nov 26 '25 04:11

goodoldneon777


1 Answers

You need to use your select component into itself recursively. The important parts are:

  • Define an input parameter corresponding to the options (and children)
  • Check if there is something to display
  • Detect select box changes so you can initialize the default current element

Here is a possible implementation:

import {Component,Input} from 'angular2/core';
import {FieldSelect,FieldOption} from './data';

@Component({
  selector: 'sel',
  template: `
    <div class="root">
      <select *ngIf="options && options.length>0" (change)="onChange($event.target.value)">
        <option *ngFor="#option of options" [value]="option.value">{{option.text}}</option>
      </select>
      <sel *ngIf="currentOption" [options]="currentOption.children"></sel>
    </div>
  `,
  directives: [ SelectComponent ]
})
export class SelectComponent {
  @Input()
  options:FieldOption[];

  constructor() {
  }

  ngOnInit() {
    if (this.options && this.options.length > 0) {
      this.currentOption = this.options[0];
    } else {
      this.currentOption = null;
    }
  }

  onChange(opt) {
    let i = this.options.findIndex(elt => elt.value === opt);
    if (i >= 0) {
      this.currentOption = this.options[i];
    } else {
      this.currentOption = null;
    }
  }

  ngOnChanges() {
    if (this.options && this.options.length > 0) {
      this.currentOption = this.options[0];
    } else {
      this.currentOption = null;
    }
  }
}

Then you can import this component and use it into another one, as described below:

import {Component,Input} from 'angular2/core';
import {FieldSelect,FieldOption} from './data';
import {SelectComponent} from './custom.select';

@Component({
  selector: 'my-app',
  template: `
    <sel [options]="select.options"></sel>
  `,
  directives: [ SelectComponent ]
})
export class AppComponent {
  constructor() {
    var options = [
      (...)
    ];
    this.select = new FieldSelect(options);
  }
}

I used this data structure:

var options = [
  {
    text:'Temperature',
    value: 'temperature',
    children: [
      { 
        text: 'Single test',
        value: 'singlke-test',
        children: [
          { 
            text: 'Degas arrive',
            value: 'degas-arrive',
            children: [
            ]
          }
        ]
      }
    ]
  },
  {
    text:'Temperature1',
    value: 'temperature1',
    children: [
      { text: 'Single test1',
        value: 'singlke-test1',
        children: [
        ]
      }
    ]
  }
];

See this plunkr for more details: https://plnkr.co/edit/VutmZOpbNd15TxJnBqpE?p=preview

Hope it helps you, Thierry

like image 152
Thierry Templier Avatar answered Nov 28 '25 20:11

Thierry Templier