All files / src/app/shared/components/select select.component.ts

100% Statements 100/100
90.7% Branches 39/43
100% Functions 25/25
100% Lines 82/82

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 15198x 98x   98x 98x   98x 98x 98x             98x   98x   98x   98x   98x   98x   98x   98x     98x       90x 90x   90x   98x 115x 115x 20x   115x 115x     98x 115x 115x 115x     98x 56x 45x 25x 20x     98x 31x 31x 76x     98x 55x       19x   36x 36x 36x     151x 151x 151x 391x 123x     151x     191x 532x     98x 33x 119x 66x         98x 66x 5x   66x 53x   13x     98x 15x 7x   8x 8x       98x 7x 1x   6x 6x     98x 12x       2x       98x 14x 14x     98x 9x 30x     98x  
import { Component, EventEmitter, Input, OnChanges, OnInit, Output } from '@angular/core';
import { FormControl, ValidatorFn } from '@angular/forms';
 
import { I18n } from '@ngx-translate/i18n-polyfill';
import * as _ from 'lodash';
 
import { CdFormGroup } from '../../forms/cd-form-group';
import { SelectMessages } from './select-messages.model';
import { SelectOption } from './select-option.model';
 
@Component({
  selector: 'cd-select',
  template: require('./select.component.html'),
  styles: []
})
export class SelectComponent implements OnInit, OnChanges {
  @Input()
  elemClass: string;
  @Input()
  data: Array<string> = [];
  @Input()
  options: Array<SelectOption> = [];
  @Input()
  messages = new SelectMessages({}, this.i18n);
  @Input()
  selectionLimit: number;
  @Input()
  customBadges = false;
  @Input()
  customBadgeValidators: ValidatorFn[] = [];
 
  @Output()
  selection = new EventEmitter();
 
  form: CdFormGroup;
  filter: FormControl;
  Object = Object;
  filteredOptions: Array<SelectOption> = [];
 
  constructor(private i18n: I18n) {}
 
  ngOnInit() {
    this.initFilter();
    if (this.data.length > 0) {
      this.initMissingOptions();
    }
    this.options = _.sortBy(this.options, ['name']);
    this.updateOptions();
  }
 
  private initFilter() {
    this.filter = new FormControl('', { validators: this.customBadgeValidators });
    this.form = new CdFormGroup({ filter: this.filter });
    this.filteredOptions = [...(this.options || [])];
  }
 
  private initMissingOptions() {
    const options = this.options.map((option) => option.name);
    const needToCreate = this.data.filter((option) => options.indexOf(option) === -1);
    needToCreate.forEach((option) => this.addOption(option));
    this.forceOptionsToReflectData();
  }
 
  private addOption(name: string) {
    this.options.push(new SelectOption(false, name, ''));
    this.options = _.sortBy(this.options, ['name']);
    this.triggerSelection(this.options.find((option) => option.name === name));
  }
 
  triggerSelection(option: SelectOption) {
    if (
      !option ||
      (this.selectionLimit && !option.selected && this.data.length >= this.selectionLimit)
    ) {
      return;
    }
    option.selected = !option.selected;
    this.updateOptions();
    this.selection.emit({ option: option });
  }
 
  private updateOptions() {
    this.data.splice(0, this.data.length);
    this.options.forEach((option: SelectOption) => {
      if (option.selected) {
        this.data.push(option.name);
      }
    });
    this.updateFilter();
  }
 
  updateFilter() {
    this.filteredOptions = this.options.filter((option) => option.name.includes(this.filter.value));
  }
 
  private forceOptionsToReflectData() {
    this.options.forEach((option) => {
      if (this.data.indexOf(option.name) !== -1) {
        option.selected = true;
      }
    });
  }
 
  ngOnChanges() {
    if (this.filter) {
      this.updateFilter();
    }
    if (!this.options || !this.data || this.data.length === 0) {
      return;
    }
    this.forceOptionsToReflectData();
  }
 
  selectOption() {
    if (this.filteredOptions.length === 0) {
      this.addCustomOption();
    } else {
      this.triggerSelection(this.filteredOptions[0]);
      this.resetFilter();
    }
  }
 
  addCustomOption() {
    if (!this.isCreatable()) {
      return;
    }
    this.addOption(this.filter.value);
    this.resetFilter();
  }
 
  isCreatable() {
    return (
      this.customBadges &&
      this.filter.valid &&
      this.filter.value.length > 0 &&
      this.filteredOptions.every((option) => option.name !== this.filter.value)
    );
  }
 
  private resetFilter() {
    this.filter.setValue('');
    this.updateFilter();
  }
 
  removeItem(item: string) {
    this.triggerSelection(
      this.options.find((option: SelectOption) => option.name === item && option.selected)
    );
  }
}