From 451ec28bda576819d457e6de725526c88e5e7457 Mon Sep 17 00:00:00 2001 From: annampak Date: Wed, 14 Feb 2018 12:38:19 +0200 Subject: [PATCH] autocomplete chips component --- dmp-admin/src/app/material/material.module.ts | 9 +- .../app/dmps/editor/dmp-editor.component.html | 8 +- .../app/dmps/editor/dmp-editor.component.ts | 6 +- .../AutoCompleteChipConfiguration.ts | 11 ++ .../autocompleteChips.component.html | 21 +++ .../autocompleteChips.component.scss | 30 ++++ .../autocompleteChips.component.ts | 163 ++++++++++++++++++ .../app/shared/material/material.module.ts | 6 +- dmp-frontend/src/app/shared/shared.module.ts | 7 +- 9 files changed, 250 insertions(+), 11 deletions(-) create mode 100644 dmp-frontend/src/app/shared/components/autocompleteChips/AutoCompleteChipConfiguration.ts create mode 100644 dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.html create mode 100644 dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.scss create mode 100644 dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.ts diff --git a/dmp-admin/src/app/material/material.module.ts b/dmp-admin/src/app/material/material.module.ts index 67c89a4dc..71b15cfc3 100644 --- a/dmp-admin/src/app/material/material.module.ts +++ b/dmp-admin/src/app/material/material.module.ts @@ -22,7 +22,8 @@ import { MatProgressSpinnerModule, DateAdapter, MatTooltipModule, - MatTabsModule + MatTabsModule, + MatChipsModule } from '@angular/material'; import { CdkTableModule } from '@angular/cdk/table'; import { LocalizedDateAdapter } from './date/LocalizedDateAdapter'; @@ -52,7 +53,8 @@ import { SnackBarNotificationComponent } from 'app/shared/notification/snack-bar MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, - MatTabsModule + MatTabsModule, + MatChipsModule ], exports: [ @@ -78,7 +80,8 @@ import { SnackBarNotificationComponent } from 'app/shared/notification/snack-bar MatProgressBarModule, MatProgressSpinnerModule, MatTooltipModule, - MatTabsModule + MatTabsModule, + MatChipsModule ], providers: [ diff --git a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.html b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.html index 4edae2d7c..dbb7ba9ef 100644 --- a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.html +++ b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.html @@ -18,9 +18,13 @@ {{'GENERAL.VALIDATION.REQUIRED' | translate}} - - + --> + + + diff --git a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.ts b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.ts index 5099433e3..4cd93e46b 100644 --- a/dmp-frontend/src/app/dmps/editor/dmp-editor.component.ts +++ b/dmp-frontend/src/app/dmps/editor/dmp-editor.component.ts @@ -1,5 +1,5 @@ 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 { TranslateService } from "@ngx-translate/core"; 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 { TdDialogService } from '@covalent/core'; import { AvailableProfilesComponent } from "@app/available-profiles/available-profiles.component"; - +import { AutoCompleteChipConfiguration } from "@app/shared/components/autocompleteChips/AutoCompleteChipConfiguration"; @Component({ selector: 'app-dmp-editor-component', @@ -48,6 +48,7 @@ export class DataManagementPlanEditorComponent implements AfterViewInit { filteredProfiles: DatasetProfileModel[]; projectAutoCompleteConfiguration: AutoCompleteConfiguration; + projectAutoCompleteConfigurationTest: AutoCompleteChipConfiguration; createNewVersion; associatedUsers: Array @@ -74,6 +75,7 @@ export class DataManagementPlanEditorComponent implements AfterViewInit { let projectRequestItem: RequestItem = new RequestItem(); projectRequestItem.criteria = new ProjectCriteria(); 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) { this.isNew = false; diff --git a/dmp-frontend/src/app/shared/components/autocompleteChips/AutoCompleteChipConfiguration.ts b/dmp-frontend/src/app/shared/components/autocompleteChips/AutoCompleteChipConfiguration.ts new file mode 100644 index 000000000..013e0fc70 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocompleteChips/AutoCompleteChipConfiguration.ts @@ -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; + constructor(callback: Function, requestItem: RequestItem) { + this.callback = callback; + this.requestItem = requestItem; + } +} diff --git a/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.html b/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.html new file mode 100644 index 000000000..f2ce8c9d9 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.html @@ -0,0 +1,21 @@ + + + + {{item.label}} + cancel + + + + {{'GENERAL.VALIDATION.REQUIRED' | translate}} + {{errorString}} + + + + {{item[titleKey]}} + {{item[subtitleKey]}} + + + + \ No newline at end of file diff --git a/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.scss b/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.scss new file mode 100644 index 000000000..6e7ec5cf9 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.scss @@ -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%; +} diff --git a/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.ts b/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.ts new file mode 100644 index 000000000..fea6b4219 --- /dev/null +++ b/dmp-frontend/src/app/shared/components/autocompleteChips/autocompleteChips.component.ts @@ -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(); + + // @Output() + // output: EventEmitter = new EventEmitter(); + + @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 = (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); + } +} \ No newline at end of file diff --git a/dmp-frontend/src/app/shared/material/material.module.ts b/dmp-frontend/src/app/shared/material/material.module.ts index d3968338f..8545c0d61 100644 --- a/dmp-frontend/src/app/shared/material/material.module.ts +++ b/dmp-frontend/src/app/shared/material/material.module.ts @@ -27,7 +27,8 @@ import { MatStepperModule, MatRadioModule, MatMenuModule, - MatListModule + MatListModule, + MatChipsModule } from '@angular/material'; import { CdkTableModule } from '@angular/cdk/table'; import { SnackBarNotificationComponent } from '../components/notificaiton/snack-bar-notification.component'; @@ -68,7 +69,8 @@ import { CovalentLayoutModule, CovalentChipsModule, CovalentDialogsModule } from MatStepperModule, MatRadioModule, MatMenuModule, - MatListModule + MatListModule, + MatChipsModule ], providers: [ diff --git a/dmp-frontend/src/app/shared/shared.module.ts b/dmp-frontend/src/app/shared/shared.module.ts index 29494870e..f037e7972 100644 --- a/dmp-frontend/src/app/shared/shared.module.ts +++ b/dmp-frontend/src/app/shared/shared.module.ts @@ -12,6 +12,7 @@ import { ProjectCriteriaComponent } from './components/criteria/projects/project import { DatasetCriteriaComponent } from './components/criteria/datasets/datasets-criteria.component'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { DataManagementPlanCriteriaComponent } from './components/criteria/data-management-plan/dmp-criteria.component'; +import { AutocompleteChipComponent } from '@app/shared/components/autocompleteChips/autocompleteChips.component'; @NgModule({ imports: [ @@ -31,7 +32,8 @@ import { DataManagementPlanCriteriaComponent } from './components/criteria/data- DataManagementPlanCriteriaComponent, AutocompleteComponent, FigurecardComponent, - BaseCriteriaComponent + BaseCriteriaComponent, + AutocompleteChipComponent ], exports: [ @@ -43,7 +45,8 @@ import { DataManagementPlanCriteriaComponent } from './components/criteria/data- DataManagementPlanCriteriaComponent, AutocompleteComponent, FigurecardComponent, - BaseCriteriaComponent + BaseCriteriaComponent, + AutocompleteChipComponent ], entryComponents: [ ]