autocomplete chips component
This commit is contained in:
parent
edde3cb050
commit
451ec28bda
|
@ -22,7 +22,8 @@ import {
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
DateAdapter,
|
DateAdapter,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatTabsModule
|
MatTabsModule,
|
||||||
|
MatChipsModule
|
||||||
} from '@angular/material';
|
} from '@angular/material';
|
||||||
import { CdkTableModule } from '@angular/cdk/table';
|
import { CdkTableModule } from '@angular/cdk/table';
|
||||||
import { LocalizedDateAdapter } from './date/LocalizedDateAdapter';
|
import { LocalizedDateAdapter } from './date/LocalizedDateAdapter';
|
||||||
|
@ -52,7 +53,8 @@ import { SnackBarNotificationComponent } from 'app/shared/notification/snack-bar
|
||||||
MatProgressBarModule,
|
MatProgressBarModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatTabsModule
|
MatTabsModule,
|
||||||
|
MatChipsModule
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
|
@ -78,7 +80,8 @@ import { SnackBarNotificationComponent } from 'app/shared/notification/snack-bar
|
||||||
MatProgressBarModule,
|
MatProgressBarModule,
|
||||||
MatProgressSpinnerModule,
|
MatProgressSpinnerModule,
|
||||||
MatTooltipModule,
|
MatTooltipModule,
|
||||||
MatTabsModule
|
MatTabsModule,
|
||||||
|
MatChipsModule
|
||||||
],
|
],
|
||||||
|
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -18,9 +18,13 @@
|
||||||
<mat-error *ngIf="formGroup.get('description').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
<mat-error *ngIf="formGroup.get('description').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<auto-complete class="mat-form-field-full-width" placeholder="{{'DMP-EDITOR.FIELDS.PROJECT' | translate}}" [configuration]="projectAutoCompleteConfiguration"
|
<!-- <auto-complete class="mat-form-field-full-width" placeholder="{{'DMP-EDITOR.FIELDS.PROJECT' | translate}}" [configuration]="projectAutoCompleteConfiguration"
|
||||||
titleKey="label" [control]="formGroup.get('project')" [required]="true">
|
titleKey="label" [control]="formGroup.get('project')" [required]="true">
|
||||||
</auto-complete>
|
</auto-complete> -->
|
||||||
|
|
||||||
|
<auto-complete-chip class="mat-form-field-full-width" placeholder="{{'DMP-EDITOR.FIELDS.PROJECT' | translate}}" [configuration]="projectAutoCompleteConfiguration"
|
||||||
|
titleKey="label" [control]="formGroup.get('project')" [required]="true">
|
||||||
|
</auto-complete-chip>
|
||||||
|
|
||||||
<td-chips color="accent" [items]="filteredProfiles" formControlName="profiles" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}"
|
<td-chips color="accent" [items]="filteredProfiles" formControlName="profiles" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}"
|
||||||
(inputChange)="filterProfiles($event)" requireMatch required>
|
(inputChange)="filterProfiles($event)" requireMatch required>
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Component, ViewChild, OnInit, AfterViewInit, ViewEncapsulation } from "@angular/core";
|
import { Component, ViewChild, OnInit, AfterViewInit, ViewEncapsulation } from "@angular/core";
|
||||||
import { MatPaginator, MatSort, MatSnackBar, MatDialog } from "@angular/material";
|
import { MatPaginator, MatSort, MatSnackBar, MatDialog, MatChipList, MatChip } from "@angular/material";
|
||||||
import { Router, ActivatedRoute, Params } from "@angular/router";
|
import { Router, ActivatedRoute, Params } from "@angular/router";
|
||||||
import { TranslateService } from "@ngx-translate/core";
|
import { TranslateService } from "@ngx-translate/core";
|
||||||
import { DataSource } from "@angular/cdk/table";
|
import { DataSource } from "@angular/cdk/table";
|
||||||
|
@ -24,7 +24,7 @@ import { AddResearchersComponent } from "@app/add-researchers/add-researchers.co
|
||||||
import { ViewContainerRef } from '@angular/core';
|
import { ViewContainerRef } from '@angular/core';
|
||||||
import { TdDialogService } from '@covalent/core';
|
import { TdDialogService } from '@covalent/core';
|
||||||
import { AvailableProfilesComponent } from "@app/available-profiles/available-profiles.component";
|
import { AvailableProfilesComponent } from "@app/available-profiles/available-profiles.component";
|
||||||
|
import { AutoCompleteChipConfiguration } from "@app/shared/components/autocompleteChips/AutoCompleteChipConfiguration";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dmp-editor-component',
|
selector: 'app-dmp-editor-component',
|
||||||
|
@ -48,6 +48,7 @@ export class DataManagementPlanEditorComponent implements AfterViewInit {
|
||||||
filteredProfiles: DatasetProfileModel[];
|
filteredProfiles: DatasetProfileModel[];
|
||||||
|
|
||||||
projectAutoCompleteConfiguration: AutoCompleteConfiguration;
|
projectAutoCompleteConfiguration: AutoCompleteConfiguration;
|
||||||
|
projectAutoCompleteConfigurationTest: AutoCompleteChipConfiguration;
|
||||||
createNewVersion;
|
createNewVersion;
|
||||||
associatedUsers: Array<DmpUsersModel>
|
associatedUsers: Array<DmpUsersModel>
|
||||||
|
|
||||||
|
@ -74,6 +75,7 @@ export class DataManagementPlanEditorComponent implements AfterViewInit {
|
||||||
let projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
|
let projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
|
||||||
projectRequestItem.criteria = new ProjectCriteria();
|
projectRequestItem.criteria = new ProjectCriteria();
|
||||||
this.projectAutoCompleteConfiguration = new AutoCompleteConfiguration(this.projectService.getWithExternal.bind(this.projectService), projectRequestItem);
|
this.projectAutoCompleteConfiguration = new AutoCompleteConfiguration(this.projectService.getWithExternal.bind(this.projectService), projectRequestItem);
|
||||||
|
this.projectAutoCompleteConfigurationTest = new AutoCompleteChipConfiguration(this.projectService.getWithExternal.bind(this.projectService), projectRequestItem);
|
||||||
|
|
||||||
if (itemId != null) {
|
if (itemId != null) {
|
||||||
this.isNew = false;
|
this.isNew = false;
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
import { BaseCriteria } from "../../../models/criteria/BaseCriteria";
|
||||||
|
import { RequestItem } from "../../../models/criteria/RequestItem";
|
||||||
|
|
||||||
|
export class AutoCompleteChipConfiguration {
|
||||||
|
public callback: Function;
|
||||||
|
public requestItem: RequestItem<any>;
|
||||||
|
constructor(callback: Function, requestItem: RequestItem<any>) {
|
||||||
|
this.callback = callback;
|
||||||
|
this.requestItem = requestItem;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
<mat-form-field>
|
||||||
|
<mat-chip-list #chipList>
|
||||||
|
<mat-chip *ngFor="let item of selectedItems" (remove)="remove(item)">
|
||||||
|
{{item.label}}
|
||||||
|
<mat-icon matChipRemove>cancel</mat-icon>
|
||||||
|
</mat-chip>
|
||||||
|
<input matInput [matAutocomplete]="auto" [matChipInputFor]="chipList" [formControl]="control" placeholder="{{placeholder}}" [required]="required">
|
||||||
|
</mat-chip-list>
|
||||||
|
<mat-error *ngIf="control.errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
<mat-error *ngIf="validationErrorString">{{errorString}}</mat-error>
|
||||||
|
<mat-progress-spinner matSuffix mode="indeterminate" *ngIf="loading" [diameter]="22"></mat-progress-spinner>
|
||||||
|
<mat-autocomplete #auto="matAutocomplete" [displayWith]="displayWith.bind(this)" (optionSelected)="this.optionSelected($event)">
|
||||||
|
<mat-option *ngFor="let item of filteredItems " [value]="item">
|
||||||
|
<span *ngIf="titleKey">{{item[titleKey]}}</span>
|
||||||
|
<span *ngIf="subtitleKey">{{item[subtitleKey]}}</span>
|
||||||
|
</mat-option>
|
||||||
|
<!-- <mat-option *ngIf="filteredItems.length == 0" value="das">
|
||||||
|
<span>{{'GENERAL.AUTOCOMPLETE.NO-ITEMS' | translate}}</span>
|
||||||
|
</mat-option> -->
|
||||||
|
</mat-autocomplete>
|
||||||
|
</mat-form-field>
|
|
@ -0,0 +1,30 @@
|
||||||
|
.autocomplete-input {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete-progress {
|
||||||
|
overflow: initial !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.autocomplete {
|
||||||
|
mat-form-field {
|
||||||
|
width: 100%;
|
||||||
|
padding: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mat-card {
|
||||||
|
margin: 16px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.left-button {
|
||||||
|
float: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-table {
|
||||||
|
table-layout: fixed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.full-width {
|
||||||
|
width: 100%;
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
import { any } from 'codelyzer/util/function';
|
||||||
|
import { FormControl, FormGroupDirective, NgForm, FormGroup, FormBuilder } from '@angular/forms';
|
||||||
|
import { Observable } from 'rxjs/Rx';
|
||||||
|
import { setTimeout } from 'timers';
|
||||||
|
import { Component, EventEmitter, Input, OnInit, Output, ViewChild, ElementRef } from '@angular/core';
|
||||||
|
import 'rxjs/add/operator/debounceTime';
|
||||||
|
import 'rxjs/add/operator/map';
|
||||||
|
import { AutoCompleteChipConfiguration } from './AutoCompleteChipConfiguration';
|
||||||
|
import { ErrorStateMatcher, MatInput } from '@angular/material';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'auto-complete-chip',
|
||||||
|
templateUrl: './autocompleteChips.component.html',
|
||||||
|
styleUrls: ['./autocompleteChips.component.scss']
|
||||||
|
})
|
||||||
|
export class AutocompleteChipComponent implements OnInit {
|
||||||
|
@Input()
|
||||||
|
configuration: AutoCompleteChipConfiguration;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
titleKey: String;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
subtitleKey: String;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
delay: number = 700;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
placeholder: String;
|
||||||
|
|
||||||
|
filteredItems: any[];
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
required: boolean;
|
||||||
|
|
||||||
|
@Input()
|
||||||
|
disabled: boolean = false;
|
||||||
|
|
||||||
|
// @Input() selectedDropdownItem: AutoCompleteItem;
|
||||||
|
// @Output() selectedDropdownItemChange = new EventEmitter<AutoCompleteItem>();
|
||||||
|
|
||||||
|
// @Output()
|
||||||
|
// output: EventEmitter<AutoCompleteItem> = new EventEmitter<AutoCompleteItem>();
|
||||||
|
|
||||||
|
@Input() control: FormControl;
|
||||||
|
|
||||||
|
// @Input() createNew = false;
|
||||||
|
// //term = new FormControl();
|
||||||
|
// @Input()
|
||||||
|
// ClickFunctionCall: Function;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
hasSelectedItem = false;
|
||||||
|
|
||||||
|
selectedItems: any[] = [];
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
|
const valueChanges = this.control.valueChanges.share();
|
||||||
|
valueChanges.subscribe(searchTerm => {
|
||||||
|
if (this.hasSelectedItem) { //proswrina epeidh ta projects den eixan ids...gia test!!!
|
||||||
|
this.resetFormControlValue();
|
||||||
|
} else {
|
||||||
|
this.loading = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
valueChanges
|
||||||
|
.debounceTime(this.delay)
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.switchMap(val => {
|
||||||
|
if (this.hasSelectedItem) {
|
||||||
|
this.loading = false;
|
||||||
|
return [];
|
||||||
|
} else if (typeof(val)== "string") {
|
||||||
|
this.configuration.requestItem.criteria.like = val;
|
||||||
|
return this.configuration.callback(this.configuration.requestItem).map(result => {
|
||||||
|
this.filteredItems = (<any[]>result)
|
||||||
|
this.loading = false;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}).subscribe()
|
||||||
|
}
|
||||||
|
|
||||||
|
resetFormControlValue() {
|
||||||
|
this.hasSelectedItem = false;
|
||||||
|
//this.control.setValue(null, { emitEvent: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
// // listingItemToDropDown(item: DropdownListingItem): AutoCompleteItem {
|
||||||
|
// // return (item as DropdownListingItem).toDropdownList();
|
||||||
|
// // }
|
||||||
|
|
||||||
|
optionSelected(event: any) {
|
||||||
|
this.hasSelectedItem = true;
|
||||||
|
this.selectedItems.push(event.option.value)
|
||||||
|
this.control.setValue(this.selectedItems, { emitEvent: false });
|
||||||
|
this.filteredItems = this.selectedItems;
|
||||||
|
|
||||||
|
//this.selectedDropdownItemChange.emit(event.option.value);
|
||||||
|
//this.form.updateValueAndValidity();
|
||||||
|
//this.options = [event.option.value];
|
||||||
|
//this.loading = false;
|
||||||
|
}
|
||||||
|
remove(item:any){
|
||||||
|
// this.selectedItems.filter(function(selitem){
|
||||||
|
// return selitem.id != item.id;
|
||||||
|
// });
|
||||||
|
const index: number = this.selectedItems.indexOf(item);
|
||||||
|
if (index !== -1) {
|
||||||
|
this.selectedItems.splice(index, 1);
|
||||||
|
}
|
||||||
|
this.control.setValue(this.selectedItems);
|
||||||
|
|
||||||
|
if(this.selectedItems.length == 0) this.hasSelectedItem = false;
|
||||||
|
}
|
||||||
|
// inputOnChange(term: string) {
|
||||||
|
// //this.form.patchValue({ value: null, description: '', text: '' });
|
||||||
|
// //this.form.updateValueAndValidity();
|
||||||
|
// this.configuration.criteria.like = term;
|
||||||
|
// this.configuration.callback(this.configuration.criteria)
|
||||||
|
// .map((res: any) => this.mapper(res))
|
||||||
|
// .subscribe(
|
||||||
|
// (res: AutoCompleteItem[]) => {
|
||||||
|
// this.options = res;
|
||||||
|
// },
|
||||||
|
// null,
|
||||||
|
// () => { this.loading = false });
|
||||||
|
// }
|
||||||
|
|
||||||
|
displayWith(value: any): String {
|
||||||
|
if (!value) return '';
|
||||||
|
if (value.lenght) {
|
||||||
|
value.forEach(element => {
|
||||||
|
element['' + this.titleKey];
|
||||||
|
});
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
else return value['' + this.titleKey];
|
||||||
|
|
||||||
|
}
|
||||||
|
// displayFn(item: AutoCompleteItem): string {
|
||||||
|
// return item.text ? item.text : '';
|
||||||
|
// }
|
||||||
|
|
||||||
|
//fieldHasErrors(control: FormControl, form: FormGroupDirective | NgForm): boolean {
|
||||||
|
// return this.errorStateMatcher(control, form);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class AutoCompleteErrorStateMatcher implements ErrorStateMatcher {
|
||||||
|
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
|
||||||
|
const isFormSubmitted = form && form.submitted;
|
||||||
|
const isControlInvalid = control && control.invalid && (control.dirty || control.touched || isFormSubmitted);
|
||||||
|
const isFormInvalid = form && form.enabled && form.invalid && (form.dirty || form.touched || isFormSubmitted)
|
||||||
|
return !!(isControlInvalid || isFormInvalid);
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,8 @@ import {
|
||||||
MatStepperModule,
|
MatStepperModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
MatListModule
|
MatListModule,
|
||||||
|
MatChipsModule
|
||||||
} from '@angular/material';
|
} from '@angular/material';
|
||||||
import { CdkTableModule } from '@angular/cdk/table';
|
import { CdkTableModule } from '@angular/cdk/table';
|
||||||
import { SnackBarNotificationComponent } from '../components/notificaiton/snack-bar-notification.component';
|
import { SnackBarNotificationComponent } from '../components/notificaiton/snack-bar-notification.component';
|
||||||
|
@ -68,7 +69,8 @@ import { CovalentLayoutModule, CovalentChipsModule, CovalentDialogsModule } from
|
||||||
MatStepperModule,
|
MatStepperModule,
|
||||||
MatRadioModule,
|
MatRadioModule,
|
||||||
MatMenuModule,
|
MatMenuModule,
|
||||||
MatListModule
|
MatListModule,
|
||||||
|
MatChipsModule
|
||||||
],
|
],
|
||||||
|
|
||||||
providers: [
|
providers: [
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { ProjectCriteriaComponent } from './components/criteria/projects/project
|
||||||
import { DatasetCriteriaComponent } from './components/criteria/datasets/datasets-criteria.component';
|
import { DatasetCriteriaComponent } from './components/criteria/datasets/datasets-criteria.component';
|
||||||
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
import { FormsModule, ReactiveFormsModule } from '@angular/forms';
|
||||||
import { DataManagementPlanCriteriaComponent } from './components/criteria/data-management-plan/dmp-criteria.component';
|
import { DataManagementPlanCriteriaComponent } from './components/criteria/data-management-plan/dmp-criteria.component';
|
||||||
|
import { AutocompleteChipComponent } from '@app/shared/components/autocompleteChips/autocompleteChips.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -31,7 +32,8 @@ import { DataManagementPlanCriteriaComponent } from './components/criteria/data-
|
||||||
DataManagementPlanCriteriaComponent,
|
DataManagementPlanCriteriaComponent,
|
||||||
AutocompleteComponent,
|
AutocompleteComponent,
|
||||||
FigurecardComponent,
|
FigurecardComponent,
|
||||||
BaseCriteriaComponent
|
BaseCriteriaComponent,
|
||||||
|
AutocompleteChipComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
|
@ -43,7 +45,8 @@ import { DataManagementPlanCriteriaComponent } from './components/criteria/data-
|
||||||
DataManagementPlanCriteriaComponent,
|
DataManagementPlanCriteriaComponent,
|
||||||
AutocompleteComponent,
|
AutocompleteComponent,
|
||||||
FigurecardComponent,
|
FigurecardComponent,
|
||||||
BaseCriteriaComponent
|
BaseCriteriaComponent,
|
||||||
|
AutocompleteChipComponent
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue