File
Implements
Metadata
selector |
cd-select |
styleUrls |
./select.component.scss |
templateUrl |
./select.component.html |
Index
Properties
|
|
Methods
|
|
Inputs
|
|
Outputs
|
|
Constructor
constructor(i18n: I18n)
|
|
Parameters :
Name |
Type |
Optional |
i18n |
I18n
|
No
|
|
customBadges
|
Default value : false
|
|
customBadgeValidators
|
Type : ValidatorFn[]
|
Default value : []
|
|
data
|
Type : Array<string>
|
Default value : []
|
|
messages
|
Type : SelectMessages
|
Default value : new SelectMessages({}, this.i18n)
|
|
Methods
addCustomOption
|
addCustomOption()
|
|
|
Private
addOption
|
addOption(name: string)
|
|
Parameters :
Name |
Type |
Optional |
name |
string
|
No
|
|
Private
forceOptionsToReflectData
|
forceOptionsToReflectData()
|
|
|
Private
initFilter
|
initFilter()
|
|
|
Private
initMissingOptions
|
initMissingOptions()
|
|
|
isCreatable
|
isCreatable()
|
|
|
ngOnChanges
|
ngOnChanges()
|
|
|
removeItem
|
removeItem(item: string)
|
|
Parameters :
Name |
Type |
Optional |
item |
string
|
No
|
|
Private
resetFilter
|
resetFilter()
|
|
|
selectOption
|
selectOption()
|
|
|
updateFilter
|
updateFilter()
|
|
|
Private
updateOptions
|
updateOptions()
|
|
|
Object
|
Default value : Object
|
|
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',
templateUrl: './select.component.html',
styleUrls: ['./select.component.scss']
})
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)
);
}
}
<ng-template #popTemplate>
<form name="form"
#formDir="ngForm"
[formGroup]="form"
novalidate>
<div [ngClass]="{'has-error': form.showError('filter', formDir)}">
<input type="text"
formControlName="filter"
i18n-placeholder
[placeholder]="messages.filter"
(keyup)="$event.keyCode == 13 ? selectOption() : updateFilter()"
class="form-control text-center" />
<ng-container *ngFor="let error of Object.keys(messages.customValidations)">
<span class="help-block text-center"
*ngIf="form.showError('filter', formDir) && filter.hasError(error)">
{{ messages.customValidations[error] }}
</span>
</ng-container>
</div>
</form>
<div *ngFor="let option of filteredOptions"
class="select-menu-item"
[class.disabled]="data.length === selectionLimit && !option.selected"
(click)="triggerSelection(option)">
<div class="select-menu-item-icon">
<i class="fa fa-check"
aria-hidden="true"
*ngIf="option.selected"></i>
</div>
<div class="select-menu-item-content">
{{ option.name }}
<ng-container *ngIf="option.description">
<br>
<small class="text-muted">
{{ option.description }}
</small>
</ng-container>
</div>
</div>
<div *ngIf="isCreatable()"
class="select-menu-item"
(click)="addCustomOption(filter.value)">
<div class="select-menu-item-icon">
<i class="fa fa-tag"
aria-hidden="true"></i>
</div>
<div class="select-menu-item-content">
{{ messages.add }} '{{ filter.value }}'
</div>
</div>
<div class="has-warning"
*ngIf="data.length === selectionLimit">
<span class="help-block text-center text-warning"
[tooltip]="messages.selectionLimit.tooltip"
*ngIf="data.length === selectionLimit">
{{ messages.selectionLimit.text }}
</span>
</div>
</ng-template>
<a class="select-menu-edit"
[ngClass]="elemClass"
[popover]="popTemplate"
placement="bottom"
container="body"
outsideClick="true"
*ngIf="options.length > 0">
<ng-content></ng-content>
</a>
<span class="text-muted"
*ngIf="data.length === 0 && options.length > 0">
{{ messages.empty }}
</span>
<span class="text-muted"
*ngIf="options.length === 0">
{{ messages.noOptions }}
</span>
@import '../../../../defaults';
.select-menu-item {
display: block;
cursor: pointer;
border-bottom: 1px solid $color-transparent;
font-size: 12px;
&:hover {
background-color: $color-whitesmoke-gray;
}
}
.select-menu-item-icon {
float: left;
padding: 0.5em;
width: 3em;
}
.select-menu-item-content {
padding: 0.5em;
}
Legend
Html element with directive