Project

General

Profile

1 59618 k.triantaf
import {Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges, ViewChild} from "@angular/core";
2 60310 k.triantaf
import {AbstractControl, FormArray, FormControl} from "@angular/forms";
3 59831 k.triantaf
import {HelperFunctions} from "../../utils/HelperFunctions.class";
4 60310 k.triantaf
import {Observable, of, Subscription} from "rxjs";
5 59618 k.triantaf
import {MatSelect} from "@angular/material/select";
6 60310 k.triantaf
import {MatAutocompleteSelectedEvent} from "@angular/material/autocomplete";
7
import {map, startWith} from "rxjs/operators";
8 57673 k.triantaf
9 57941 k.triantaf
10
export interface Option {
11
  icon?: string,
12
  iconClass?: string,
13
  value: any,
14
  label: string
15
}
16
17 57673 k.triantaf
@Component({
18
  selector: '[dashboard-input]',
19
  template: `
20 60310 k.triantaf
    <div *ngIf="label && type != 'checkbox'"
21
         class="uk-text-bold uk-form-label uk-margin-small-bottom">{{label + (required ? ' *' : '')}}</div>
22 59618 k.triantaf
    <div *ngIf="hint" class="uk-margin-bottom uk-text-small uk-form-hint">{{hint}}</div>
23 60274 k.triantaf
    <div class="uk-grid uk-flex uk-flex-middle" [class.uk-grid-small]="gridSmall" uk-grid>
24 59618 k.triantaf
      <ng-content></ng-content>
25 60310 k.triantaf
      <div [class.uk-hidden]="hideControl" class="uk-width-expand uk-position-relative"
26
           [class.uk-flex-first]="!extraLeft">
27 60182 k.triantaf
        <ng-template [ngIf]="icon && formControl.enabled">
28 59731 k.triantaf
          <span class="uk-text-muted" [ngClass]="iconLeft?('left'):'right'">
29
            <icon [name]="icon"></icon>
30
          </span>
31
        </ng-template>
32 60182 k.triantaf
        <ng-template [ngIf]="formControl.disabled">
33
          <span class="uk-text-muted left">
34
            <icon [name]="'lock'"></icon>
35
          </span>
36
        </ng-template>
37 59618 k.triantaf
        <ng-template [ngIf]="type === 'text'">
38 60310 k.triantaf
          <input class="uk-input input-box uk-text-small"
39
                 [attr.uk-tooltip]="formControl.disabled?'title: This field is not editable; pos: bottom-left':''"
40
                 [placeholder]="placeholder" [formControl]="formControl"
41 59618 k.triantaf
                 [class.uk-form-danger]="formControl.invalid && formControl.touched">
42
        </ng-template>
43
        <ng-template [ngIf]="type === 'textarea'">
44 60310 k.triantaf
          <textarea class="uk-textarea input-box uk-text-small"
45
                    [attr.uk-tooltip]="formControl.disabled?'title: This field is not editable; pos: bottom-left':''"
46
                    [rows]="rows" [placeholder]="placeholder"
47 59623 k.triantaf
                    [formControl]="formControl" [class.uk-form-danger]="formControl.invalid && formControl.touched">
48
          </textarea>
49 59618 k.triantaf
        </ng-template>
50
        <ng-template [ngIf]="type === 'select'">
51 60310 k.triantaf
          <div class="input-box"
52
               [attr.uk-tooltip]="formControl.disabled?'title: This field is not editable; pos: bottom-left':null"
53
               [class.clickable]="formControl.enabled"
54
               [class.uk-form-danger]="formControl.invalid && formControl.touched" (click)="openSelect()">
55 59618 k.triantaf
            <mat-form-field class="uk-width-1-1">
56 60310 k.triantaf
              <mat-select #select [required]="required" [value]="null"
57
                          (openedChange)="stopPropagation()" [formControl]="formControl"
58
                          [disableOptionCentering]="true">
59 59627 k.triantaf
                <mat-option *ngIf="placeholder" class="uk-hidden" [value]="''">{{placeholder}}</mat-option>
60 59618 k.triantaf
                <mat-option *ngFor="let option of options" [value]="option.value">
61
                  {{option.label}}
62
                </mat-option>
63
              </mat-select>
64
            </mat-form-field>
65
          </div>
66
        </ng-template>
67 60310 k.triantaf
        <ng-template [ngIf]="type === 'chips'">
68
          <div class="input-box"
69
               [attr.uk-tooltip]="formControl.disabled?'title: This field is not editable; pos: bottom-left':null"
70
               [class.clickable]="formControl.enabled"
71
               [class.uk-form-danger]="formControl.invalid && formControl.touched" (click)="openSelect()">
72
            <mat-form-field class="uk-width-1-1">
73
              <mat-chip-list #chipList aria-label="Page selection">
74
                <mat-chip *ngFor="let chip of formAsArray.controls; let i=index"
75
                          [removable]="removable">
76
                  {{chip.value[chipLabel]}}
77 60326 k.triantaf
                  <icon name="remove_circle" class="mat-chip-remove" (click)="removed(i)"></icon>
78 60310 k.triantaf
                </mat-chip>
79 60326 k.triantaf
                <div class="uk-width-expand uk-position-relative uk-text-small chip-input">
80 60310 k.triantaf
                  <input #searchInput class="uk-width-1-1" [formControl]="searchControl" [matAutocomplete]="auto" [matChipInputFor]="chipList">
81
                  <div *ngIf="placeholder && !searchControl.value" class="placeholder uk-width-1-1"
82
                       (click)="searchInput.focus()">{{placeholder}}</div>
83
                </div>
84
              </mat-chip-list>
85
              <mat-autocomplete #auto="matAutocomplete" (optionSelected)="selected($event)">
86
                <mat-option *ngFor="let option of filteredOptions | async" [value]="option.value">
87
                  {{option.label}}
88
                </mat-option>
89
              </mat-autocomplete>
90
            </mat-form-field>
91
          </div>
92
        </ng-template>
93
        <span *ngIf="formControl.invalid && formControl.errors.error"
94
              class="uk-text-danger input-message">{{formControl.errors.error}}</span>
95 60274 k.triantaf
        <span *ngIf="warning" class="uk-text-warning input-message">{{warning}}</span>
96
        <span *ngIf="note" class="input-message">{{note}}</span>
97 59618 k.triantaf
      </div>
98
    </div>
99
    <mat-checkbox *ngIf="type === 'checkbox'" [formControl]="formControl">{{label}}</mat-checkbox>
100 59731 k.triantaf
  `,
101
  styleUrls: ['input.component.css']
102 57673 k.triantaf
})
103 59618 k.triantaf
export class InputComponent implements OnInit, OnDestroy, OnChanges {
104 57768 k.triantaf
  @Input('formInput') formControl: AbstractControl;
105 60310 k.triantaf
  @Input('type') type: 'text' | 'textarea' | 'select' | 'checkbox' | 'chips' = 'text';
106 57673 k.triantaf
  @Input('label') label: string;
107
  @Input('rows') rows: number = 3;
108
  @Input('options') options: Option[];
109 59618 k.triantaf
  @Input('hint') hint = null;
110
  @Input('placeholder') placeholder = '';
111
  @ViewChild('select') select: MatSelect;
112
  @Input() extraLeft: boolean = true;
113 60274 k.triantaf
  @Input() gridSmall: boolean = false;
114 59623 k.triantaf
  @Input() hideControl: boolean = false;
115 59731 k.triantaf
  @Input() icon: string = null;
116
  @Input() iconLeft: boolean = false;
117 59810 k.triantaf
  @Input() warning: string = null;
118 60274 k.triantaf
  @Input() note: string = null;
119 60310 k.triantaf
  @Input() removable: boolean = true;
120
  @Input() chipLabel: string = null;
121
  public filteredOptions: Observable<Option[]>;
122
  public searchControl: FormControl;
123 58864 k.triantaf
  public required: boolean = false;
124 57735 k.triantaf
  private initValue: any;
125 59618 k.triantaf
  private subscriptions: any[] = [];
126 60310 k.triantaf
  @ViewChild('searchInput') searchInput;
127 59618 k.triantaf
128 57673 k.triantaf
  constructor() {
129
  }
130 59618 k.triantaf
131 57673 k.triantaf
  ngOnInit(): void {
132 59618 k.triantaf
    this.reset();
133
  }
134
135
  ngOnChanges(changes: SimpleChanges) {
136
    if(changes.formControl) {
137
      this.reset();
138
    }
139
  }
140
141 60310 k.triantaf
  get formAsArray(): FormArray {
142
    return (<FormArray> this.formControl);
143
  }
144
145 59618 k.triantaf
  reset() {
146
    this.unsubscribe();
147 57735 k.triantaf
    this.initValue = HelperFunctions.copy(this.formControl.value);
148 60310 k.triantaf
    if(this.options && this.type === 'chips') {
149
      this.filteredOptions = of(this.options);
150
      this.searchControl = new FormControl('');
151
      this.filteredOptions = this.searchControl.valueChanges.pipe(startWith(''),
152
        map(option => this.filter(option)));
153
    }
154 59618 k.triantaf
    if (this.formControl && this.formControl.validator) {
155 58864 k.triantaf
      let validator = this.formControl.validator({} as AbstractControl);
156
      this.required = (validator && validator.required);
157
    }
158 59618 k.triantaf
    this.subscriptions.push(this.formControl.valueChanges.subscribe(value => {
159 57979 k.triantaf
      value = (value === '')?null:value;
160 59735 k.triantaf
      if(this.initValue === value || (this.initValue === '' && value === null)) {
161 57735 k.triantaf
        this.formControl.markAsPristine();
162
      }
163 59618 k.triantaf
    }));
164
    if (!this.formControl.value) {
165
      this.formControl.setValue('');
166
    }
167
  }
168
169
  unsubscribe() {
170
    this.subscriptions.forEach(subscription => {
171
      if(subscription instanceof Subscription) {
172
        subscription.unsubscribe();
173
      }
174 57735 k.triantaf
    });
175 57673 k.triantaf
  }
176 59618 k.triantaf
177
  openSelect() {
178
    if(this.select) {
179
      this.select.open();
180
    }
181
  }
182
183 57673 k.triantaf
  ngOnDestroy(): void {
184 59618 k.triantaf
    this.unsubscribe();
185 57673 k.triantaf
  }
186 59618 k.triantaf
187 57708 k.triantaf
  stopPropagation() {
188 59618 k.triantaf
    event.stopPropagation();
189 57708 k.triantaf
  }
190 60310 k.triantaf
191
  removed(index: number) {
192
    this.formAsArray.removeAt(index);
193
    this.formAsArray.markAsDirty();
194
  }
195
196
  selected(event: MatAutocompleteSelectedEvent): void {
197
    this.formAsArray.push(new FormControl(event.option.value));
198
    this.formAsArray.markAsDirty();
199
    this.searchControl.setValue('');
200
    this.searchInput.nativeElement.value = '';
201
  }
202
203
  private filter(value: string): Option[] {
204
    let options = this.options.filter(option => !this.formAsArray.value.find(value => option.label === value[this.chipLabel]));
205
    if (!value || value.length == 0) {
206
      return options;
207
    }
208
    const filterValue = value.toString().toLowerCase();
209
    return options.filter(option => option.label.toLowerCase().indexOf(filterValue) != -1);
210
  }
211 57673 k.triantaf
}