no message
This commit is contained in:
parent
14f9be46f0
commit
32eff9b523
|
@ -33,7 +33,7 @@ public class Organisations extends BaseController {
|
||||||
try {
|
try {
|
||||||
List<Map<String, String>> remoteRepos = this.getApiContext().getOperationsContext().getRemoteFetcher().getOrganisations(query,type);
|
List<Map<String, String>> remoteRepos = this.getApiContext().getOperationsContext().getRemoteFetcher().getOrganisations(query,type);
|
||||||
OrganisationsExternalSourcesModel projectsExternalSourcesModel = new OrganisationsExternalSourcesModel().fromExternalItem(remoteRepos);
|
OrganisationsExternalSourcesModel projectsExternalSourcesModel = new OrganisationsExternalSourcesModel().fromExternalItem(remoteRepos);
|
||||||
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<OrganisationsExternalSourcesModel>().payload(projectsExternalSourcesModel).status(ApiMessageCode.SUCCESS_MESSAGE));
|
return ResponseEntity.status(HttpStatus.OK).body(new ResponseItem<OrganisationsExternalSourcesModel>().payload(projectsExternalSourcesModel).status(ApiMessageCode.NO_MESSAGE));
|
||||||
} catch (NoURLFound ex) {
|
} catch (NoURLFound ex) {
|
||||||
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<OrganisationsExternalSourcesModel>().status(ApiMessageCode.ERROR_MESSAGE).message("External Url Not Found"));
|
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ResponseItem<OrganisationsExternalSourcesModel>().status(ApiMessageCode.ERROR_MESSAGE).message("External Url Not Found"));
|
||||||
} catch (HugeResultSet ex) {
|
} catch (HugeResultSet ex) {
|
||||||
|
|
|
@ -19,7 +19,6 @@ import { Component, ViewChild, OnInit, AfterViewInit, ViewEncapsulation, Templat
|
||||||
import { FormGroup, Validators, FormBuilder, FormArray } from "@angular/forms";
|
import { FormGroup, Validators, FormBuilder, FormArray } from "@angular/forms";
|
||||||
import * as FileSaver from 'file-saver';
|
import * as FileSaver from 'file-saver';
|
||||||
import { MatPaginator, MatSort, MatSnackBar, MatStepper } from "@angular/material";
|
import { MatPaginator, MatSort, MatSnackBar, MatStepper } from "@angular/material";
|
||||||
import { AutoCompleteConfiguration } from '../../shared/components/autocomplete/AutoCompleteConfiguration';
|
|
||||||
import { ExternalDatasetCriteria } from '../../models/criteria/external-dataset/ExternalDatasetCriteria';
|
import { ExternalDatasetCriteria } from '../../models/criteria/external-dataset/ExternalDatasetCriteria';
|
||||||
import { ExternalDatasetModel } from '../../models/external-dataset/ExternalDatasetModel';
|
import { ExternalDatasetModel } from '../../models/external-dataset/ExternalDatasetModel';
|
||||||
import { RegistryCriteria } from '../../models/criteria/registry/RegistryCriteria';
|
import { RegistryCriteria } from '../../models/criteria/registry/RegistryCriteria';
|
||||||
|
@ -35,6 +34,7 @@ import { Observable } from 'rxjs/Observable';
|
||||||
import { BreadcrumbItem } from '../../shared/components/breadcrumb/definition/breadcrumb-item';
|
import { BreadcrumbItem } from '../../shared/components/breadcrumb/definition/breadcrumb-item';
|
||||||
import { TagsCriteria } from '../../models/criteria/tags/TagsCriteria';
|
import { TagsCriteria } from '../../models/criteria/tags/TagsCriteria';
|
||||||
import { TagModel } from '../../models/tags/TagModel';
|
import { TagModel } from '../../models/tags/TagModel';
|
||||||
|
import { AutoCompleteConfiguration } from '../../shared/components/auto-complete/AutoCompleteConfiguration';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dataset-wizard-component',
|
selector: 'app-dataset-wizard-component',
|
||||||
|
|
|
@ -44,67 +44,45 @@
|
||||||
<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="col-md-6" placeholder="{{this.languageResolverService.getBy('dmpEditor') | translate}}" [configuration]="projectAutoCompleteConfiguration"
|
<div class="col-md-6">
|
||||||
titleKey="label" [control]="formGroup.get('project')" [required]="true">
|
<app-single-auto-complete [reactiveFormControl]="formGroup.get('project')" placeholder="{{this.languageResolverService.getBy('dmpEditor') | translate}}"
|
||||||
</auto-complete>
|
[configuration]="projectAutoCompleteConfiguration">
|
||||||
|
</app-single-auto-complete>
|
||||||
|
</div>
|
||||||
<!-- <app-dynamic-fields-project [formGroup]="formGroup"></app-dynamic-fields-project> -->
|
<!-- <app-dynamic-fields-project [formGroup]="formGroup"></app-dynamic-fields-project> -->
|
||||||
|
<div class="col-md-6">
|
||||||
<td-chips class="col-md-6" color="accent" [items]="filteredProfiles" formControlName="profiles" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}"
|
<div class="row">
|
||||||
(inputChange)="filterProfiles($event)" requireMatch required>
|
<app-multiple-auto-complete class="col-md-10" [reactiveFormControl]="formGroup.get('profiles')" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}"
|
||||||
<ng-template td-chip let-chip="chip">
|
[configuration]="profilesAutoCompleteConfiguration">
|
||||||
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.label.substring(0, 1).toUpperCase()}}</div>
|
</app-multiple-auto-complete>
|
||||||
{{chip.label}}
|
<div class="col-md-2">
|
||||||
</ng-template>
|
<button mat-icon-button type="button" (click)="availableProfiles()">
|
||||||
<ng-template td-autocomplete-option let-option="option">
|
<mat-icon>view_list</mat-icon>
|
||||||
<div>
|
</button>
|
||||||
{{option.label}}
|
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</div>
|
||||||
<mat-progress-bar [style.height.px]="2" *ngIf="filteredProfilesAsync" mode="indeterminate"></mat-progress-bar>
|
</div>
|
||||||
<span *ngIf="formGroup.get('profiles').touched || !formGroup.get('profiles').pristine">
|
|
||||||
<mat-error style="font-size:10.5px" *ngIf="formGroup.get('profiles').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</span>
|
|
||||||
</td-chips>
|
|
||||||
<!-- <button mat-button (click)="availableProfiles()">View All</button> -->
|
<!-- <button mat-button (click)="availableProfiles()">View All</button> -->
|
||||||
<a style="float:right" href="#" (click)="availableProfiles()">View All</a>
|
|
||||||
|
|
||||||
<!-- <auto-complete-chip placeholder="{{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}" [configuration]="organisationsAutoCompleteConfiguration"
|
|
||||||
titleKey="name" [control]="formGroup.get('organisations')" [required]="true">
|
|
||||||
</auto-complete-chip> -->
|
|
||||||
|
|
||||||
<td-chips class="col-md-6" color="accent" [items]="filteredOrganisations" formControlName="organisations" placeholder="{{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}"
|
|
||||||
(inputChange)="filterOrganisations($event)" requireMatch>
|
|
||||||
<ng-template td-chip let-chip="chip">
|
|
||||||
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.name.substring(0, 1).toUpperCase()}}</div>
|
|
||||||
{{chip.name}}
|
|
||||||
</ng-template>
|
|
||||||
<ng-template td-autocomplete-option let-option="option">
|
|
||||||
<div>
|
|
||||||
{{option.name}}
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
<mat-progress-bar [style.height.px]="2" *ngIf="filteringOrganisationsAsync" mode="indeterminate"></mat-progress-bar>
|
|
||||||
</td-chips>
|
|
||||||
|
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<td-chips style="margin-bottom:25px; display:inline-block; width:90%" color="accent" [items]="filteredResearchers" formControlName="researchers"
|
<app-multiple-auto-complete [reactiveFormControl]="formGroup.get('organisations')" placeholder="{{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}"
|
||||||
placeholder="{{'DMP-EDITOR.FIELDS.RESEARCHERS' | translate}}" (inputChange)="filterResearchers($event)" requireMatch>
|
[configuration]="organisationsAutoCompleteConfiguration">
|
||||||
<ng-template td-chip let-chip="chip">
|
</app-multiple-auto-complete>
|
||||||
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.name.substring(0, 1).toUpperCase()}}</div>
|
</div>
|
||||||
{{chip.name}}
|
<div class="col-md-6">
|
||||||
</ng-template>
|
<div class="row">
|
||||||
<ng-template td-autocomplete-option let-option="option">
|
<div class="col-md-10">
|
||||||
<div>
|
<app-multiple-auto-complete [reactiveFormControl]="formGroup.get('researchers')" placeholder="{{'DMP-EDITOR.FIELDS.RESEARCHERS' | translate}}"
|
||||||
{{option.name}}
|
[configuration]="researchersAutoCompleteConfiguration">
|
||||||
</div>
|
</app-multiple-auto-complete>
|
||||||
</ng-template>
|
</div>
|
||||||
<mat-progress-bar [style.height.px]="2" *ngIf="filteringResearchersAsync" mode="indeterminate"></mat-progress-bar>
|
<div class="col-md-2">
|
||||||
</td-chips>
|
<button mat-icon-button type="button" (click)="addResearcher()">
|
||||||
|
<mat-icon>add_circle</mat-icon>
|
||||||
<button style="display:inline-block;" mat-icon-button type="button" (click)="addResearcher()">
|
</button>
|
||||||
<mat-icon aria-label="Example icon-button with a heart icon">add_circle</mat-icon>
|
</div>
|
||||||
</button>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<h3 mat-subheader class="col-md-12">{{'DMP-EDITOR.FIELDS.PROFILE' | translate}}</h3>
|
<h3 mat-subheader class="col-md-12">{{'DMP-EDITOR.FIELDS.PROFILE' | translate}}</h3>
|
||||||
|
|
|
@ -16,7 +16,6 @@ import { RequestItem } from "../../models/criteria/RequestItem";
|
||||||
import { DatasetProfileCriteria } from "../../models/criteria/dataset/DatasetProfileCriteria";
|
import { DatasetProfileCriteria } from "../../models/criteria/dataset/DatasetProfileCriteria";
|
||||||
import { DataManagementPlanCriteriaComponent } from "../../shared/components/criteria/data-management-plan/dmp-criteria.component";
|
import { DataManagementPlanCriteriaComponent } from "../../shared/components/criteria/data-management-plan/dmp-criteria.component";
|
||||||
import { DatasetProfileModel } from "../../models/datasets/DatasetProfileModel";
|
import { DatasetProfileModel } from "../../models/datasets/DatasetProfileModel";
|
||||||
import { AutoCompleteConfiguration } from "../../shared/components/autocomplete/AutoCompleteConfiguration";
|
|
||||||
import { ProjectCriteria } from "../../models/criteria/project/ProjectCriteria";
|
import { ProjectCriteria } from "../../models/criteria/project/ProjectCriteria";
|
||||||
import { ProjectService } from "../../services/project/project.service";
|
import { ProjectService } from "../../services/project/project.service";
|
||||||
import { DmpUsersModel } from "../../models/dmpUsers/DmpUsersModel";
|
import { DmpUsersModel } from "../../models/dmpUsers/DmpUsersModel";
|
||||||
|
@ -32,6 +31,8 @@ import { DataManagementPlanProfile } from "../../models/data-management-plan-pro
|
||||||
import { LanguageResolverService } from "../../services/language-resolver/language-resolver.service";
|
import { LanguageResolverService } from "../../services/language-resolver/language-resolver.service";
|
||||||
import { IBreadCrumbComponent } from "../../shared/components/breadcrumb/definition/IBreadCrumbComponent";
|
import { IBreadCrumbComponent } from "../../shared/components/breadcrumb/definition/IBreadCrumbComponent";
|
||||||
import { BreadcrumbItem } from "../../shared/components/breadcrumb/definition/breadcrumb-item";
|
import { BreadcrumbItem } from "../../shared/components/breadcrumb/definition/breadcrumb-item";
|
||||||
|
import { SingleAutoCompleteConfiguration } from "../../shared/components/autocompletes/single/single-auto-complete-configuration";
|
||||||
|
import { MultipleAutoCompleteConfiguration } from "../../shared/components/autocompletes/multiple/multiple-auto-complete-configuration";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dmp-editor-component',
|
selector: 'app-dmp-editor-component',
|
||||||
|
@ -55,7 +56,11 @@ export class DataManagementPlanEditorComponent implements AfterViewInit, IBreadC
|
||||||
filteredResearchers: ExternalSourcesItemModel[];
|
filteredResearchers: ExternalSourcesItemModel[];
|
||||||
filteredProfiles: DatasetProfileModel[];
|
filteredProfiles: DatasetProfileModel[];
|
||||||
|
|
||||||
projectAutoCompleteConfiguration: AutoCompleteConfiguration;
|
projectAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||||
|
profilesAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
|
||||||
|
organisationsAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
|
||||||
|
researchersAutoCompleteConfiguration: MultipleAutoCompleteConfiguration;
|
||||||
|
|
||||||
createNewVersion;
|
createNewVersion;
|
||||||
associatedUsers: Array<DmpUsersModel>
|
associatedUsers: Array<DmpUsersModel>
|
||||||
filteredOptions: Observable<DataManagementPlanProfileListingModel>
|
filteredOptions: Observable<DataManagementPlanProfileListingModel>
|
||||||
|
@ -86,7 +91,42 @@ export class DataManagementPlanEditorComponent implements AfterViewInit, IBreadC
|
||||||
projectRequestItem.criteria = new ProjectCriteria();
|
projectRequestItem.criteria = new ProjectCriteria();
|
||||||
let organisationRequestItem: RequestItem<BaseCriteria> = new RequestItem();
|
let organisationRequestItem: RequestItem<BaseCriteria> = new RequestItem();
|
||||||
organisationRequestItem.criteria = new BaseCriteria();
|
organisationRequestItem.criteria = new BaseCriteria();
|
||||||
this.projectAutoCompleteConfiguration = new AutoCompleteConfiguration(this.projectService.getWithExternal.bind(this.projectService), projectRequestItem);
|
//this.projectAutoCompleteConfiguration = new AutoCompleteConfiguration(this.projectService.getWithExternal.bind(this.projectService), projectRequestItem);
|
||||||
|
|
||||||
|
|
||||||
|
this.projectAutoCompleteConfiguration = {
|
||||||
|
filterFn: this.searchProject.bind(this),
|
||||||
|
items: this.searchProject(''),
|
||||||
|
displayFn: (item) => item["label"],
|
||||||
|
titleFn: (item) => item["label"],
|
||||||
|
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
|
||||||
|
loadDataOnStart: true
|
||||||
|
};
|
||||||
|
|
||||||
|
this.profilesAutoCompleteConfiguration = {
|
||||||
|
filterFn: this.filterProfiles.bind(this),
|
||||||
|
initialItems: (excludedItems: any[]) => this.filterProfiles('').map(result => result.filter(x => excludedItems.map(x => x.id).indexOf(x.id) == -1)),
|
||||||
|
displayFn: (item) => item["label"],
|
||||||
|
titleFn: (item) => item["label"],
|
||||||
|
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
|
||||||
|
loadDataOnStart: true
|
||||||
|
};
|
||||||
|
|
||||||
|
this.organisationsAutoCompleteConfiguration = {
|
||||||
|
filterFn: this.filterOrganisations.bind(this),
|
||||||
|
initialItems: (excludedItems: any[]) => this.filterOrganisations('').map(result => result.filter(x => excludedItems.map(x => x.id).indexOf(x.id) == -1)),
|
||||||
|
displayFn: (item) => item["name"],
|
||||||
|
titleFn: (item) => item["name"],
|
||||||
|
loadDataOnStart: true
|
||||||
|
};
|
||||||
|
|
||||||
|
this.researchersAutoCompleteConfiguration = {
|
||||||
|
filterFn: this.filterResearchers.bind(this),
|
||||||
|
initialItems: (excludedItems: any[]) => this.filterResearchers('').map(result => result.filter(x => excludedItems.map(x => x.id).indexOf(x.id) == -1)),
|
||||||
|
displayFn: (item) => item["name"],
|
||||||
|
titleFn: (item) => item["name"],
|
||||||
|
loadDataOnStart: true
|
||||||
|
};
|
||||||
|
|
||||||
if (itemId != null) {
|
if (itemId != null) {
|
||||||
this.isNew = false;
|
this.isNew = false;
|
||||||
|
@ -133,6 +173,13 @@ export class DataManagementPlanEditorComponent implements AfterViewInit, IBreadC
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
searchProject(query: string) {
|
||||||
|
let projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
|
||||||
|
projectRequestItem.criteria = new ProjectCriteria();
|
||||||
|
projectRequestItem.criteria.like = query;
|
||||||
|
return this.projectService.getWithExternal(projectRequestItem);
|
||||||
|
}
|
||||||
|
|
||||||
formSubmit(): void {
|
formSubmit(): void {
|
||||||
//this.touchAllFormFields(this.formGroup);
|
//this.touchAllFormFields(this.formGroup);
|
||||||
if (!this.isFormValid()) { return; }
|
if (!this.isFormValid()) { return; }
|
||||||
|
@ -177,54 +224,32 @@ export class DataManagementPlanEditorComponent implements AfterViewInit, IBreadC
|
||||||
this.router.navigate(['/invite/' + this.dataManagementPlan.id]);
|
this.router.navigate(['/invite/' + this.dataManagementPlan.id]);
|
||||||
}
|
}
|
||||||
|
|
||||||
filterOrganisations(value: string): void {
|
filterOrganisations(value: string): Observable<ExternalSourcesItemModel[]> {
|
||||||
|
|
||||||
this.filteredOrganisations = undefined;
|
this.filteredOrganisations = undefined;
|
||||||
if (value) {
|
this.filteringOrganisationsAsync = true;
|
||||||
this.filteringOrganisationsAsync = true;
|
|
||||||
|
|
||||||
this.externalSourcesService.searchDMPOrganizations(value).subscribe(items => {
|
return this.externalSourcesService.searchDMPOrganizations(value)
|
||||||
this.filteredOrganisations = items;
|
|
||||||
this.filteringOrganisationsAsync = false;
|
|
||||||
|
|
||||||
// this.filteredOrganisations = items.filter((filteredObj: any) => {
|
|
||||||
// return this.objectsModel ? this.objectsModel.indexOf(filteredObj) < 0 : true;
|
|
||||||
// });
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filterResearchers(value: string): void {
|
filterResearchers(value: string): Observable<ExternalSourcesItemModel[]> {
|
||||||
|
|
||||||
this.filteredResearchers = undefined;
|
this.filteredResearchers = undefined;
|
||||||
if (value) {
|
this.filteringResearchersAsync = true;
|
||||||
this.filteringResearchersAsync = true;
|
|
||||||
|
|
||||||
this.externalSourcesService.searchDMPResearchers({ criteria: { name: value, like: null } }).subscribe(items => {
|
return this.externalSourcesService.searchDMPResearchers({ criteria: { name: value, like: null } })
|
||||||
this.filteredResearchers = items;
|
|
||||||
this.filteringResearchersAsync = false;
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
filterProfiles(value: string): void {
|
filterProfiles(value: string): Observable<DatasetProfileModel[]> {
|
||||||
|
|
||||||
this.filteredProfiles = undefined;
|
this.filteredProfiles = undefined;
|
||||||
if (value) {
|
this.filteredProfilesAsync = true;
|
||||||
this.filteredProfilesAsync = true;
|
|
||||||
|
|
||||||
const request = new RequestItem<DatasetProfileCriteria>();
|
const request = new RequestItem<DatasetProfileCriteria>();
|
||||||
let criteria = new DatasetProfileCriteria();
|
let criteria = new DatasetProfileCriteria();
|
||||||
criteria.like = value;
|
criteria.like = value;
|
||||||
request.criteria = criteria;
|
request.criteria = criteria;
|
||||||
this._service.searchDMPProfiles(request).subscribe(items => {
|
return this._service.searchDMPProfiles(request)
|
||||||
this.filteredProfiles = items;
|
|
||||||
this.filteredProfilesAsync = false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addResearcher(rowId: any, rowName: any) {
|
addResearcher(rowId: any, rowName: any) {
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
import { Component, ViewEncapsulation, OnInit, Input, ViewChild } from "@angular/core";
|
import { Component, ViewEncapsulation, OnInit, Input, ViewChild } from "@angular/core";
|
||||||
import { FormGroup } from "@angular/forms";
|
import { FormGroup } from "@angular/forms";
|
||||||
import { DataManagementPlanService } from "../../../../services/data-management-plan/data-management-plan.service";
|
import { DataManagementPlanService } from "../../../../services/data-management-plan/data-management-plan.service";
|
||||||
import { AutoCompleteConfiguration } from "../../../../shared/components/autocomplete/AutoCompleteConfiguration";
|
|
||||||
import { RequestItem } from "../../../../models/criteria/RequestItem";
|
import { RequestItem } from "../../../../models/criteria/RequestItem";
|
||||||
import { DynamicFieldProjectCriteria, DynamicFieldProjectCriteriaDependencies } from "../../../../models/dynamic-field-project/DynamicFieldProjectCriteria";
|
import { DynamicFieldProjectCriteria, DynamicFieldProjectCriteriaDependencies } from "../../../../models/dynamic-field-project/DynamicFieldProjectCriteria";
|
||||||
import { AutoCompleteComponent } from "../../../../shared/components/auto-complete/auto-complete.component";
|
import { AutoCompleteComponent } from "../../../../shared/components/auto-complete/auto-complete.component";
|
||||||
import { DynamicFieldDependency } from "../../../../models/data-managemnt-plans/DynamicFieldDependency";
|
import { DynamicFieldDependency } from "../../../../models/data-managemnt-plans/DynamicFieldDependency";
|
||||||
import { LanguageResolverService } from "../../../../services/language-resolver/language-resolver.service";
|
import { LanguageResolverService } from "../../../../services/language-resolver/language-resolver.service";
|
||||||
|
import { AutoCompleteConfiguration } from "../../../../shared/components/auto-complete/AutoCompleteConfiguration";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-dynamic-field-project',
|
selector: 'app-dynamic-field-project',
|
||||||
|
|
|
@ -1,86 +1,83 @@
|
||||||
<div class="data-management-plan-wizard-editor">
|
<div class="data-management-plan-wizard-editor">
|
||||||
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup">
|
<form *ngIf="formGroup" (ngSubmit)="formSubmit()" [formGroup]="formGroup">
|
||||||
<mat-card>
|
<mat-card>
|
||||||
<mat-card-content>
|
<mat-card-content>
|
||||||
<mat-form-field class="full-width">
|
<mat-form-field class="full-width">
|
||||||
<input matInput placeholder="{{'DMP-EDITOR.FIELDS.NAME' | translate}}" type="text" name="label" formControlName="label" required
|
<input matInput placeholder="{{'DMP-EDITOR.FIELDS.NAME' | translate}}" type="text" name="label" formControlName="label" required
|
||||||
[attr.disabled]="labelDisabled">
|
[attr.disabled]="labelDisabled">
|
||||||
<mat-error *ngIf="formGroup.get('label').errors?.backendError">{{baseErrorModel.label}}</mat-error>
|
<mat-error *ngIf="formGroup.get('label').errors?.backendError">{{baseErrorModel.label}}</mat-error>
|
||||||
<mat-error *ngIf="formGroup.get('label').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
<mat-error *ngIf="formGroup.get('label').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field class="full-width">
|
<mat-form-field class="full-width">
|
||||||
<textarea matInput class="description-area" placeholder="{{'DMP-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description"
|
<textarea matInput class="description-area" placeholder="{{'DMP-EDITOR.FIELDS.DESCRIPTION' | translate}}" formControlName="description"
|
||||||
required></textarea>
|
required></textarea>
|
||||||
<mat-error *ngIf="formGroup.get('description').errors?.backendError">{{errorModel.description}}</mat-error>
|
<mat-error *ngIf="formGroup.get('description').errors?.backendError">{{errorModel.description}}</mat-error>
|
||||||
<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"
|
|
||||||
titleKey="label" [control]="formGroup.get('project')" [required]="true">
|
|
||||||
</auto-complete>
|
|
||||||
|
|
||||||
<td-chips color="accent" [items]="filteredProfiles" formControlName="profiles" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}"
|
<app-single-auto-complete [reactiveFormControl]="formGroup.get('project')" placeholder="{{this.languageResolverService.getBy('dmpEditor') | translate}}"
|
||||||
(inputChange)="filterProfiles($event)" requireMatch>
|
[configuration]="projectAutoCompleteConfiguration">
|
||||||
<ng-template td-chip let-chip="chip">
|
</app-single-auto-complete>
|
||||||
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.label.substring(0, 1).toUpperCase()}}</div>
|
|
||||||
{{chip.label}}
|
|
||||||
</ng-template>
|
|
||||||
<ng-template td-autocomplete-option let-option="option">
|
|
||||||
<div layout="row" layout-align="start center">
|
|
||||||
{{option.label}}
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
<mat-progress-bar [style.height.px]="2" *ngIf="filteredProfilesAsync" mode="indeterminate"></mat-progress-bar>
|
|
||||||
<mat-error style="font-size:10.5px" *ngIf="formGroup.get('profiles').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</td-chips>
|
|
||||||
|
|
||||||
<!-- <auto-complete-chip class="mat-form-field-full-width" placeholder="{{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}" [configuration]="organisationsAutoCompleteConfiguration"
|
<td-chips color="accent" [items]="filteredProfiles" formControlName="profiles" placeholder="{{'DMP-EDITOR.FIELDS.PROFILES' | translate}}"
|
||||||
titleKey="name" [control]="formGroup.get('organisations')" [required]="true">
|
(inputChange)="filterProfiles($event)" requireMatch>
|
||||||
</auto-complete-chip> -->
|
<ng-template td-chip let-chip="chip">
|
||||||
|
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.label.substring(0, 1).toUpperCase()}}</div>
|
||||||
|
{{chip.label}}
|
||||||
|
</ng-template>
|
||||||
|
<ng-template td-autocomplete-option let-option="option">
|
||||||
|
<div layout="row" layout-align="start center">
|
||||||
|
{{option.label}}
|
||||||
|
</div>
|
||||||
|
</ng-template>
|
||||||
|
<mat-progress-bar [style.height.px]="2" *ngIf="filteredProfilesAsync" mode="indeterminate"></mat-progress-bar>
|
||||||
|
<mat-error style="font-size:10.5px" *ngIf="formGroup.get('profiles').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
</td-chips>
|
||||||
|
|
||||||
<td-chips color="accent" [items]="filteredOrganisations" formControlName="organisations" placeholder="{{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}"
|
<td-chips color="accent" [items]="filteredOrganisations" formControlName="organisations" placeholder="{{'DMP-EDITOR.FIELDS.ORGANISATIONS' | translate}}"
|
||||||
(inputChange)="filterOrganisations($event)" requireMatch>
|
(inputChange)="filterOrganisations($event)" requireMatch>
|
||||||
<ng-template td-chip let-chip="chip">
|
<ng-template td-chip let-chip="chip">
|
||||||
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.name.substring(0, 1).toUpperCase()}}</div>
|
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.name.substring(0, 1).toUpperCase()}}</div>
|
||||||
{{chip.name}}
|
{{chip.name}}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template td-autocomplete-option let-option="option">
|
<ng-template td-autocomplete-option let-option="option">
|
||||||
<div layout="row" layout-align="start center">
|
<div layout="row" layout-align="start center">
|
||||||
{{option.name}}
|
{{option.name}}
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<mat-progress-bar [style.height.px]="2" *ngIf="filteringOrganisationsAsync" mode="indeterminate"></mat-progress-bar>
|
<mat-progress-bar [style.height.px]="2" *ngIf="filteringOrganisationsAsync" mode="indeterminate"></mat-progress-bar>
|
||||||
</td-chips>
|
</td-chips>
|
||||||
|
|
||||||
<td-chips style="margin-bottom:25px;" color="accent" [items]="filteredResearchers" formControlName="researchers" placeholder="{{'DMP-EDITOR.FIELDS.RESEARCHERS' | translate}}"
|
<td-chips style="margin-bottom:25px;" color="accent" [items]="filteredResearchers" formControlName="researchers" placeholder="{{'DMP-EDITOR.FIELDS.RESEARCHERS' | translate}}"
|
||||||
(inputChange)="filterResearchers($event)" requireMatch>
|
(inputChange)="filterResearchers($event)" requireMatch>
|
||||||
<ng-template td-chip let-chip="chip">
|
<ng-template td-chip let-chip="chip">
|
||||||
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.name.substring(0, 1).toUpperCase()}}</div>
|
<div class="tc-grey-100 bgc-teal-700" td-chip-avatar>{{chip.name.substring(0, 1).toUpperCase()}}</div>
|
||||||
{{chip.name}}
|
{{chip.name}}
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template td-autocomplete-option let-option="option">
|
<ng-template td-autocomplete-option let-option="option">
|
||||||
<div layout="row" layout-align="start center">
|
<div layout="row" layout-align="start center">
|
||||||
{{option.name}}
|
{{option.name}}
|
||||||
</div>
|
</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<mat-progress-bar [style.height.px]="2" *ngIf="filteringResearchersAsync" mode="indeterminate"></mat-progress-bar>
|
<mat-progress-bar [style.height.px]="2" *ngIf="filteringResearchersAsync" mode="indeterminate"></mat-progress-bar>
|
||||||
</td-chips>
|
</td-chips>
|
||||||
|
|
||||||
<mat-form-field class="full-width">
|
<mat-form-field class="full-width">
|
||||||
<input matInput placeholder="Version" formControlName="version">
|
<input matInput placeholder="Version" formControlName="version">
|
||||||
<!--disabled doesn't work -->
|
<!--disabled doesn't work -->
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-list *ngIf="associatedUsers?.length" role="list">
|
<mat-list *ngIf="associatedUsers?.length" role="list">
|
||||||
<h3 mat-subheader>Associated Users</h3>
|
<h3 mat-subheader>Associated Users</h3>
|
||||||
<mat-list-item role="listitem" *ngFor="let user of associatedUsers">
|
<mat-list-item role="listitem" *ngFor="let user of associatedUsers">
|
||||||
<mat-icon mat-list-icon>person</mat-icon>
|
<mat-icon mat-list-icon>person</mat-icon>
|
||||||
<div>{{user.name}}</div>
|
<div>{{user.name}}</div>
|
||||||
</mat-list-item>
|
</mat-list-item>
|
||||||
</mat-list>
|
</mat-list>
|
||||||
</mat-card-content>
|
</mat-card-content>
|
||||||
</mat-card>
|
</mat-card>
|
||||||
</form>
|
</form>
|
||||||
<!-- <div *ngIf="formGroup"> {{ formGroup.value | json }}</div> -->
|
<!-- <div *ngIf="formGroup"> {{ formGroup.value | json }}</div> -->
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -6,7 +6,6 @@ import { JsonSerializer } from '../../../utilities/JsonSerializer';
|
||||||
import { RequestItem } from '../../../models/criteria/RequestItem';
|
import { RequestItem } from '../../../models/criteria/RequestItem';
|
||||||
import { ProjectCriteria } from '../../../models/criteria/project/ProjectCriteria';
|
import { ProjectCriteria } from '../../../models/criteria/project/ProjectCriteria';
|
||||||
import { DmpUsersModel } from '../../../models/dmpUsers/DmpUsersModel';
|
import { DmpUsersModel } from '../../../models/dmpUsers/DmpUsersModel';
|
||||||
import { AutoCompleteConfiguration } from '../../../shared/components/autocomplete/AutoCompleteConfiguration';
|
|
||||||
import { ExternalSourcesItemModel } from '../../../models/external-sources/ExternalSourcesItemModel';
|
import { ExternalSourcesItemModel } from '../../../models/external-sources/ExternalSourcesItemModel';
|
||||||
import { DataManagementPlanModel } from '../../../models/data-managemnt-plans/DataManagementPlanModel';
|
import { DataManagementPlanModel } from '../../../models/data-managemnt-plans/DataManagementPlanModel';
|
||||||
import { ProjectService } from '../../../services/project/project.service';
|
import { ProjectService } from '../../../services/project/project.service';
|
||||||
|
@ -20,6 +19,8 @@ import { DataSource } from "@angular/cdk/table";
|
||||||
import { Observable } from "rxjs/Observable";
|
import { Observable } from "rxjs/Observable";
|
||||||
import { FormGroup } from '@angular/forms';
|
import { FormGroup } from '@angular/forms';
|
||||||
import { BaseCriteria } from '../../../models/criteria/BaseCriteria';
|
import { BaseCriteria } from '../../../models/criteria/BaseCriteria';
|
||||||
|
import { SingleAutoCompleteConfiguration } from '../../../shared/components/autocompletes/single/single-auto-complete-configuration';
|
||||||
|
import { LanguageResolverService } from '../../../services/language-resolver/language-resolver.service';
|
||||||
|
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
|
@ -41,7 +42,7 @@ export class DataManagementPlanWizardEditorComponent implements AfterViewInit {
|
||||||
filteredResearchers: ExternalSourcesItemModel[];
|
filteredResearchers: ExternalSourcesItemModel[];
|
||||||
filteredProfiles: DatasetProfileModel[];
|
filteredProfiles: DatasetProfileModel[];
|
||||||
|
|
||||||
projectAutoCompleteConfiguration: AutoCompleteConfiguration;
|
projectAutoCompleteConfiguration: SingleAutoCompleteConfiguration;
|
||||||
createNewVersion;
|
createNewVersion;
|
||||||
associatedUsers: Array<DmpUsersModel>
|
associatedUsers: Array<DmpUsersModel>
|
||||||
labelDisabled: boolean = false;
|
labelDisabled: boolean = false;
|
||||||
|
@ -54,7 +55,8 @@ export class DataManagementPlanWizardEditorComponent implements AfterViewInit {
|
||||||
public snackBar: MatSnackBar,
|
public snackBar: MatSnackBar,
|
||||||
public router: Router,
|
public router: Router,
|
||||||
public language: TranslateService,
|
public language: TranslateService,
|
||||||
private _service: DataManagementPlanService
|
private _service: DataManagementPlanService,
|
||||||
|
private languageResolverService: LanguageResolverService
|
||||||
) {
|
) {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -63,7 +65,14 @@ export class DataManagementPlanWizardEditorComponent 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 = {
|
||||||
|
filterFn: this.searchProject.bind(this.projectService),
|
||||||
|
items: this.searchProject(''),
|
||||||
|
displayFn: (item) => item["label"],
|
||||||
|
titleFn: (item) => item["label"],
|
||||||
|
//mapFn: (item) => new JsonSerializer<ProjectReference>().fromJSONArray(item, ProjectReference).map(item => item.toDropdownList()),
|
||||||
|
loadDataOnStart: true
|
||||||
|
};
|
||||||
|
|
||||||
let organisationRequestItem: RequestItem<BaseCriteria> = new RequestItem();
|
let organisationRequestItem: RequestItem<BaseCriteria> = new RequestItem();
|
||||||
organisationRequestItem.criteria = new BaseCriteria();
|
organisationRequestItem.criteria = new BaseCriteria();
|
||||||
|
@ -76,6 +85,13 @@ export class DataManagementPlanWizardEditorComponent implements AfterViewInit {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
searchProject(query: string) {
|
||||||
|
let projectRequestItem: RequestItem<ProjectCriteria> = new RequestItem();
|
||||||
|
projectRequestItem.criteria = new ProjectCriteria();
|
||||||
|
projectRequestItem.criteria.like = query;
|
||||||
|
return this.projectService.getWithExternal(projectRequestItem);
|
||||||
|
}
|
||||||
|
|
||||||
formSubmit(): void {
|
formSubmit(): void {
|
||||||
//this.touchAllFormFields(this.formGroup);
|
//this.touchAllFormFields(this.formGroup);
|
||||||
if (!this.isFormValid()) { return; }
|
if (!this.isFormValid()) { return; }
|
||||||
|
|
|
@ -3,10 +3,10 @@ import { Component, OnInit, Input, Output, EventEmitter, forwardRef, ViewEncapsu
|
||||||
import { ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
import { ControlValueAccessor, FormControl, FormGroup, NG_VALUE_ACCESSOR, Validators } from '@angular/forms';
|
||||||
import { DatasetProfileService } from '../../../services/dataset-profile.service';
|
import { DatasetProfileService } from '../../../services/dataset-profile.service';
|
||||||
import { ActivatedRoute } from '@angular/router';
|
import { ActivatedRoute } from '@angular/router';
|
||||||
import { AutoCompleteConfiguration } from '../../../shared/components/autocomplete/AutoCompleteConfiguration';
|
|
||||||
import { RequestItem } from '../../../models/criteria/RequestItem';
|
import { RequestItem } from '../../../models/criteria/RequestItem';
|
||||||
import { BaseCriteria } from '../../../models/criteria/BaseCriteria';
|
import { BaseCriteria } from '../../../models/criteria/BaseCriteria';
|
||||||
import { AutocompleteLookupItem } from '../../../models/auto-complete/AutocompleteLookupItem';
|
import { AutocompleteLookupItem } from '../../../models/auto-complete/AutocompleteLookupItem';
|
||||||
|
import { AutoCompleteConfiguration } from '../../../shared/components/auto-complete/AutoCompleteConfiguration';
|
||||||
declare var $: any;
|
declare var $: any;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ export class ProjectModel implements Serializable<ProjectModel> {
|
||||||
const baseContext: ValidationContext = new ValidationContext();
|
const baseContext: ValidationContext = new ValidationContext();
|
||||||
baseContext.validation.push({ key: 'id', validators: [] });
|
baseContext.validation.push({ key: 'id', validators: [] });
|
||||||
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'label')] });
|
baseContext.validation.push({ key: 'label', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'label')] });
|
||||||
baseContext.validation.push({ key: 'abbreviation', validators: [Validators.required, BackendErrorValidator(this.errorModel, 'abbreviation')] });
|
baseContext.validation.push({ key: 'abbreviation', validators: [BackendErrorValidator(this.errorModel, 'abbreviation')] });
|
||||||
baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.errorModel, 'uri')] });
|
baseContext.validation.push({ key: 'uri', validators: [BackendErrorValidator(this.errorModel, 'uri')] });
|
||||||
baseContext.validation.push({ key: 'type', validators: [BackendErrorValidator(this.errorModel, 'type')] });
|
baseContext.validation.push({ key: 'type', validators: [BackendErrorValidator(this.errorModel, 'type')] });
|
||||||
baseContext.validation.push({ key: 'status', validators: [] });
|
baseContext.validation.push({ key: 'status', validators: [] });
|
||||||
|
|
|
@ -28,10 +28,8 @@
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field class="col-md-6">
|
<mat-form-field class="col-md-6">
|
||||||
<input matInput placeholder="{{'PROJECT-EDITOR.FIELDS.ABBREVIATION' | translate}}" type="text" name="abbreviation" formControlName="abbreviation"
|
<input matInput placeholder="{{'PROJECT-EDITOR.FIELDS.ABBREVIATION' | translate}}" type="text" name="abbreviation" formControlName="abbreviation">
|
||||||
required>
|
|
||||||
<mat-error *ngIf="formGroup.get('abbreviation').errors?.backendError">{{baseErrorModel.abbreviation}}</mat-error>
|
<mat-error *ngIf="formGroup.get('abbreviation').errors?.backendError">{{baseErrorModel.abbreviation}}</mat-error>
|
||||||
<mat-error *ngIf="formGroup.get('abbreviation').errors?.required">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
|
||||||
</mat-form-field>
|
</mat-form-field>
|
||||||
|
|
||||||
<mat-form-field class="col-md-6">
|
<mat-form-field class="col-md-6">
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Input, OnInit, Component, AfterViewInit, Output, EventEmitter, OnChanges } from '@angular/core';
|
import { Input, OnInit, Component, AfterViewInit, Output, EventEmitter, OnChanges } from '@angular/core';
|
||||||
import { FormGroup, FormControl, FormGroupDirective, NgForm } from '@angular/forms';
|
import { FormGroup, FormControl, FormGroupDirective, NgForm } from '@angular/forms';
|
||||||
import { ErrorStateMatcher } from '@angular/material';
|
import { ErrorStateMatcher } from '@angular/material';
|
||||||
import { AutoCompleteConfiguration } from '../autocomplete/AutoCompleteConfiguration';
|
import { AutoCompleteConfiguration } from './AutoCompleteConfiguration';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-auto-complete',
|
selector: 'app-auto-complete',
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
<!-- <div [formGroup]="form" class="autocomplete">
|
|
||||||
<table class="full-width">
|
|
||||||
<tr>
|
|
||||||
<td>
|
|
||||||
<mat-form-field class="autocomplete-input">
|
|
||||||
<input matInput type="text" placeholder="{{placeholder}}" [matAutocomplete]="auto" formControlName="text" [required]="required"
|
|
||||||
[errorStateMatcher]="errorStateMatcher">
|
|
||||||
<mat-error *ngIf="form.get('value').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>
|
|
||||||
<input matInput type="text" [matAutocomplete]="auto" hidden="hidden">
|
|
||||||
</mat-form-field>
|
|
||||||
</td>
|
|
||||||
<td *ngIf="createNew">
|
|
||||||
<button mat-raised-button type="button" color="primary" (click)="this.ClickFunctionCall()" tabindex="2">{{'GENERAL.AUTOCOMPLETE.CREATE-NEW' | translate}}</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
|
|
||||||
</table>
|
|
||||||
<mat-autocomplete #auto="matAutocomplete" (optionSelected)="this.optionSelected($event)">
|
|
||||||
<mat-option *ngFor="let option of options" [value]="option">
|
|
||||||
{{ option.text }} {{option.description?'['+option.description+']':''}}
|
|
||||||
</mat-option>
|
|
||||||
</mat-autocomplete>
|
|
||||||
</div> -->
|
|
||||||
|
|
||||||
<mat-form-field class="autocomplete-input">
|
|
||||||
<input matInput [matAutocomplete]="auto" [formControl]="control" placeholder="{{placeholder}}" [required]="required">
|
|
||||||
<mat-error *ngIf="control['errors'] && control['errors']['required']">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</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>
|
|
|
@ -1,30 +0,0 @@
|
||||||
.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%;
|
|
||||||
}
|
|
|
@ -1,172 +0,0 @@
|
||||||
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 { AutoCompleteConfiguration } from './AutoCompleteConfiguration';
|
|
||||||
import { ErrorStateMatcher, MatInput } from '@angular/material';
|
|
||||||
|
|
||||||
@Component({
|
|
||||||
selector: 'auto-complete',
|
|
||||||
templateUrl: './autocomplete.component.html',
|
|
||||||
styleUrls: ['./autocomplete.component.scss']
|
|
||||||
})
|
|
||||||
export class AutocompleteComponent implements OnInit {
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
disabled = false;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
public configuration: AutoCompleteConfiguration;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
titleKey: String;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
subtitleKey: String;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
delay: number = 700;
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
placeholder: String;
|
|
||||||
|
|
||||||
filteredItems: any[];
|
|
||||||
|
|
||||||
// @Input()
|
|
||||||
// validationErrorString: String;
|
|
||||||
|
|
||||||
// public errorStateMatcher: AutoCompleteErrorStateMatcher = new AutoCompleteErrorStateMatcher();
|
|
||||||
|
|
||||||
@Input()
|
|
||||||
required: boolean;
|
|
||||||
|
|
||||||
// @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;
|
|
||||||
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
ngOnInit() {
|
|
||||||
|
|
||||||
const valueChanges = this.control.valueChanges.share();
|
|
||||||
valueChanges.subscribe(searchTerm => {
|
|
||||||
if (this.hasSelectedItem) {
|
|
||||||
this.resetFormControlValue();
|
|
||||||
} else {
|
|
||||||
this.loading = true;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
valueChanges
|
|
||||||
.debounceTime(this.delay)
|
|
||||||
.distinctUntilChanged()
|
|
||||||
.switchMap(val => {
|
|
||||||
if (this.hasSelectedItem) {
|
|
||||||
this.loading = false;
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
this.configuration.requestItem.criteria.like = this.control.value;
|
|
||||||
return this.configuration.callback(this.configuration.requestItem).map(result => {
|
|
||||||
this.filteredItems = (<any[]>result)
|
|
||||||
this.loading = false;
|
|
||||||
})
|
|
||||||
}).subscribe()
|
|
||||||
|
|
||||||
// this.filteredItems = this.inputField.nativeElement.valueChanges.startWith(null)
|
|
||||||
// .debounceTime(this.delay)
|
|
||||||
// .finally(() => this.loading = false)
|
|
||||||
// .distinctUntilChanged()
|
|
||||||
// .switchMap(val => {
|
|
||||||
// this.configuration.requestItem.criteria.like = val;
|
|
||||||
// return this.configuration.callback(this.configuration.requestItem)
|
|
||||||
// })
|
|
||||||
// const valueChanges = this.form.controls['text'].valueChanges.share();
|
|
||||||
// valueChanges.subscribe(searchTerm => {
|
|
||||||
// this.loading = true;
|
|
||||||
// if (this.form.controls['value'].value) {
|
|
||||||
// this.resetFormGroupValue();
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
// valueChanges
|
|
||||||
// .debounceTime(this.typeaheadMS)
|
|
||||||
// .subscribe(searchTerm => {
|
|
||||||
// if (typeof searchTerm === 'string') {
|
|
||||||
// this.inputOnChange(searchTerm)
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
|
||||||
|
|
||||||
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.control.setValue(event.option.value, { emitEvent: false });
|
|
||||||
this.filteredItems = [event.option.value];
|
|
||||||
|
|
||||||
//this.selectedDropdownItemChange.emit(event.option.value);
|
|
||||||
//this.form.updateValueAndValidity();
|
|
||||||
//this.options = [event.option.value];
|
|
||||||
//this.loading = 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 '';
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
export interface MultipleAutoCompleteConfiguration {
|
||||||
|
// Delay for performing the request. Default: 200ms.
|
||||||
|
requestDelay?: number;
|
||||||
|
// Min characters for the filtering to be applied. Default: 3.
|
||||||
|
minFilteringChars?: number;
|
||||||
|
// Load and present items from start, without user query. Default: true.
|
||||||
|
loadDataOnStart?: boolean;
|
||||||
|
// Static or initial items.
|
||||||
|
initialItems?: (excludedItems: any[]) => Observable<any[]>;
|
||||||
|
// Data retrieval function
|
||||||
|
filterFn?: (searchQuery: string, excludedItems: any[]) => Observable<any[]>;
|
||||||
|
// Property formating for input
|
||||||
|
displayFn?: (item: any) => string;
|
||||||
|
// Property formating for dropdown
|
||||||
|
titleFn?: (item: any) => string;
|
||||||
|
// Property formating for dropdown
|
||||||
|
subtitleFn?: (item: any) => string;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<mat-form-field class="multiple-auto-complete">
|
||||||
|
<mat-chip-list #chipList ngDefaultControl [disabled]="reactiveFormControl.disabled" [formControl]="reactiveFormControl">
|
||||||
|
<mat-chip *ngFor="let selectedItem of _chipItems()" [disabled]="reactiveFormControl.disabled" [selectable]="selectable" [removable]="removable" (removed)="_removeSelectedItem(selectedItem)">
|
||||||
|
{{this._displayFn(selectedItem)}}
|
||||||
|
<mat-icon matChipRemove *ngIf="!reactiveFormControl.disabled && removable">cancel</mat-icon>
|
||||||
|
</mat-chip>
|
||||||
|
<input matInput #textInput (focus)="_onInputFocus()" [placeholder]="placeholder" [formControl]="inputFormControl" [matAutocomplete]="auto" [matChipInputFor]="chipList" [matChipInputSeparatorKeyCodes]="separatorKeysCodes" [matChipInputAddOnBlur]="addOnBlur" (matChipInputTokenEnd)="_addItem($event)" (click)="_onInputClick($event)"/>
|
||||||
|
</mat-chip-list>
|
||||||
|
<mat-error *ngIf="validationErrorString">{{validationErrorString}}</mat-error>
|
||||||
|
<mat-error *ngIf="reactiveFormControl.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
<mat-error *ngIf="reactiveFormControl.hasError('invalidJson')">{{'GENERAL.VALIDATION.INVALID-JSON' | translate}}</mat-error>
|
||||||
|
<mat-progress-spinner matSuffix mode="indeterminate" [class.not-loading]="!loading" [diameter]="22"></mat-progress-spinner>
|
||||||
|
<mat-autocomplete #auto="matAutocomplete" [displayWith]="_displayFn.bind(this)" (optionSelected)="_optionSelected($event)">
|
||||||
|
<mat-option *ngFor="let item of _items | async" [value]="item" [class.two-line-mat-option]="_subtitleFn(item)">
|
||||||
|
<span>{{_titleFn(item)}}</span>
|
||||||
|
<br *ngIf="_subtitleFn(item)">
|
||||||
|
<small *ngIf="_subtitleFn(item)">{{_subtitleFn(item)}}</small>
|
||||||
|
</mat-option>
|
||||||
|
</mat-autocomplete>
|
||||||
|
</mat-form-field>
|
|
@ -0,0 +1,14 @@
|
||||||
|
.multiple-auto-complete {
|
||||||
|
width: 100%;
|
||||||
|
.mat-form-field {
|
||||||
|
padding: 0 3px;
|
||||||
|
}
|
||||||
|
.not-loading {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.two-line-mat-option {
|
||||||
|
height: 3.5em;
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
|
@ -0,0 +1,163 @@
|
||||||
|
import { Input, OnInit, Component, Output, EventEmitter, ViewChild, ElementRef, QueryList, AfterViewInit } from '@angular/core';
|
||||||
|
import { FormControl, FormGroupDirective, NgForm, FormArray, AbstractControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
import { ErrorStateMatcher, MatChipInputEvent, MatAutocompleteSelectedEvent, MatChipList, MatAutocompleteTrigger } from '@angular/material';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { Subject, Observable } from 'rxjs';
|
||||||
|
import { map, startWith, merge, mapTo, mergeMap, timeout } from 'rxjs/operators';
|
||||||
|
import { MultipleAutoCompleteConfiguration } from './multiple-auto-complete-configuration';
|
||||||
|
import { ENTER } from '@angular/cdk/keycodes';
|
||||||
|
import { COMMA } from '@angular/cdk/keycodes';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-multiple-auto-complete',
|
||||||
|
templateUrl: './multiple-auto-complete.component.html',
|
||||||
|
styleUrls: ['./multiple-auto-complete.component.scss']
|
||||||
|
})
|
||||||
|
export class MultipleAutoCompleteComponent implements OnInit {
|
||||||
|
|
||||||
|
@ViewChild('textInput') textInput: ElementRef;
|
||||||
|
@ViewChild(MatAutocompleteTrigger) autocomplete: MatAutocompleteTrigger;
|
||||||
|
|
||||||
|
@Input() reactiveFormControl: FormControl;
|
||||||
|
@Input() placeholder: string;
|
||||||
|
@Input() validationErrorString: string;
|
||||||
|
@Input() configuration: MultipleAutoCompleteConfiguration;
|
||||||
|
|
||||||
|
// Selected Option Event
|
||||||
|
@Output() optionSelected: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
|
private requestDelay = 200; //ms
|
||||||
|
private minFilteringChars = 3;
|
||||||
|
private loadDataOnStart = true;
|
||||||
|
|
||||||
|
loading = false;
|
||||||
|
_items: Observable<any[]>;
|
||||||
|
|
||||||
|
visible = true;
|
||||||
|
selectable = true;
|
||||||
|
removable = true;
|
||||||
|
addOnBlur = false;
|
||||||
|
separatorKeysCodes = [ENTER, COMMA];
|
||||||
|
inputFormControl: FormControl;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
this.inputFormControl = new FormControl({ value: this.reactiveFormControl.value, disabled: this.reactiveFormControl.disabled });
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(query: string): Observable<any[]> {
|
||||||
|
// If loadDataOnStart is enabled and query is empty we return the initial items.
|
||||||
|
if (this.isNullOrEmpty(query) && this.loadDataOnStart) {
|
||||||
|
return this.configuration.initialItems(this.reactiveFormControl.value || []) || Observable.of([]);
|
||||||
|
} else if (query && query.length >= this.minFilteringChars) {
|
||||||
|
if (this.configuration.filterFn) {
|
||||||
|
return this.configuration.filterFn(query, this.reactiveFormControl.value || []);
|
||||||
|
} else {
|
||||||
|
return this.configuration.initialItems(this.reactiveFormControl.value || []) || Observable.of([]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Observable.of([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isNullOrEmpty(query: string): boolean {
|
||||||
|
return typeof query !== 'string' || query === null || query.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_displayFn(item: any): string {
|
||||||
|
if (this.configuration.displayFn && item) { return this.configuration.displayFn(item); }
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
_titleFn(item: any): string {
|
||||||
|
if (this.configuration.titleFn && item) { return this.configuration.titleFn(item); }
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
_subtitleFn(item: any): string {
|
||||||
|
if (this.configuration.subtitleFn && item) { return this.configuration.subtitleFn(item); }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_requestDelay(): number {
|
||||||
|
return this.configuration.requestDelay || this.requestDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
_minFilteringChars(): number {
|
||||||
|
return this.configuration.minFilteringChars || this.minFilteringChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadDataOnStart(): boolean {
|
||||||
|
return this.configuration.loadDataOnStart || this.loadDataOnStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
_chipItems(): any[] {
|
||||||
|
return this.reactiveFormControl.value || [];
|
||||||
|
}
|
||||||
|
|
||||||
|
_optionSelected(event: MatAutocompleteSelectedEvent) {
|
||||||
|
const newValue = this.reactiveFormControl.value || [];
|
||||||
|
newValue.push(event.option.value);
|
||||||
|
this.reactiveFormControl.patchValue(newValue);
|
||||||
|
this.textInput.nativeElement.value = '';
|
||||||
|
this.inputFormControl.setValue(null);
|
||||||
|
|
||||||
|
this.optionSelected.emit(event.option.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onInputFocus() {
|
||||||
|
// We set the items observable on focus to avoid the request being executed on component load.
|
||||||
|
if (!this._items) {
|
||||||
|
this._items = this.inputFormControl.valueChanges
|
||||||
|
.startWith(null)
|
||||||
|
.debounceTime(this.requestDelay)
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.do(() => { this.loading = true; })
|
||||||
|
.flatMap(query => {
|
||||||
|
// If its a valid object, a selection just made and the object is set as the value of the form control. That means we should fire an extra request to the server.
|
||||||
|
if (this._isValidObject(query)) { return Observable.of([]); }
|
||||||
|
return this.filter(query);
|
||||||
|
})
|
||||||
|
.do(() => { this.loading = false; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isValidObject(value: any): boolean {
|
||||||
|
try {
|
||||||
|
if (!value) { return false; }
|
||||||
|
if (typeof value !== 'object') { JSON.parse(value); }
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
_removeSelectedItem(item: any): void {
|
||||||
|
const index = this.reactiveFormControl.value.indexOf(item);
|
||||||
|
if (index >= 0) {
|
||||||
|
this.reactiveFormControl.value.splice(index, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_onInputClick(item: any) {
|
||||||
|
if (!this.autocomplete.panelOpen) {
|
||||||
|
this.autocomplete.openPanel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_addItem(event: MatChipInputEvent): void {
|
||||||
|
// const input = event.input;
|
||||||
|
// const value = event.value;
|
||||||
|
// // Add our fruit
|
||||||
|
// if ((value || '').trim()) {
|
||||||
|
// this.selectedItems.push(value.trim());
|
||||||
|
// }
|
||||||
|
// // Reset the input value
|
||||||
|
// if (input) {
|
||||||
|
// input.value = '';
|
||||||
|
// }
|
||||||
|
// this.inputFormControl.setValue(null);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { Observable } from 'rxjs';
|
||||||
|
|
||||||
|
export interface SingleAutoCompleteConfiguration {
|
||||||
|
// Delay for performing the request. Default: 200ms.
|
||||||
|
requestDelay?: number;
|
||||||
|
// Min characters for the filtering to be applied. Default: 3.
|
||||||
|
minFilteringChars?: number;
|
||||||
|
// Load and present items from start, without user query. Default: true.
|
||||||
|
loadDataOnStart?: boolean;
|
||||||
|
// Static or initial items.
|
||||||
|
items?: Observable<any[]>;
|
||||||
|
// Data retrieval function
|
||||||
|
filterFn?: (searchQuery: string) => Observable<any[]>;
|
||||||
|
// Property formating for input
|
||||||
|
displayFn?: (item: any) => string;
|
||||||
|
// Property formating for dropdown
|
||||||
|
titleFn?: (item: any) => string;
|
||||||
|
// Property formating for dropdown
|
||||||
|
subtitleFn?: (item: any) => string;
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
<mat-form-field class="auto-complete">
|
||||||
|
<input matInput [placeholder]="placeholder" [matAutocomplete]="auto" [formControl]="reactiveFormControl" (focus)="_onInputFocus()">
|
||||||
|
<mat-error *ngIf="validationErrorString">{{validationErrorString}}</mat-error>
|
||||||
|
<mat-error *ngIf="reactiveFormControl.hasError('required')">{{'GENERAL.VALIDATION.REQUIRED' | translate}}</mat-error>
|
||||||
|
<mat-error *ngIf="reactiveFormControl.hasError('invalidJson')">{{'GENERAL.VALIDATION.INVALID-JSON' | translate}}</mat-error>
|
||||||
|
<mat-progress-spinner matSuffix mode="indeterminate" [class.not-loading]="!loading" [diameter]="22"></mat-progress-spinner>
|
||||||
|
<mat-autocomplete #auto="matAutocomplete" [displayWith]="this._displayFn.bind(this)" (optionSelected)="_optionSelected($event)">
|
||||||
|
<mat-option *ngFor="let item of _items | async" [value]="item" [class.two-line-mat-option]="_subtitleFn(item)">
|
||||||
|
<!-- <img style="vertical-align:middle;" aria-hidden src="{{state.flag}}" height="25" /> -->
|
||||||
|
<span>{{_titleFn(item)}}</span>
|
||||||
|
<br *ngIf="_subtitleFn(item)">
|
||||||
|
<small *ngIf="_subtitleFn(item)">{{_subtitleFn(item)}}</small>
|
||||||
|
</mat-option>
|
||||||
|
</mat-autocomplete>
|
||||||
|
</mat-form-field>
|
|
@ -0,0 +1,17 @@
|
||||||
|
.auto-complete {
|
||||||
|
width: 100%;
|
||||||
|
.mat-form-field {
|
||||||
|
padding: 0 3px;
|
||||||
|
}
|
||||||
|
.not-loading {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.two-line-mat-option {
|
||||||
|
height: 3.5em;
|
||||||
|
line-height: 1.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
// .mat-tooltip.warn-tooltip {
|
||||||
|
// background-color: mat-color($warn);
|
||||||
|
// }
|
|
@ -0,0 +1,120 @@
|
||||||
|
import { Input, OnInit, Component, Output, EventEmitter, ViewChild, ElementRef, QueryList, AfterViewInit } from '@angular/core';
|
||||||
|
import { FormControl, FormGroupDirective, NgForm, FormArray, AbstractControl, FormGroup, FormBuilder, Validators } from '@angular/forms';
|
||||||
|
import { ErrorStateMatcher, MatChipInputEvent, MatAutocompleteSelectedEvent, MatChipList } from '@angular/material';
|
||||||
|
import { TranslateService } from '@ngx-translate/core';
|
||||||
|
import { Subject , Observable } from 'rxjs';
|
||||||
|
import { map, startWith, merge, mapTo, mergeMap, timeout } from 'rxjs/operators';
|
||||||
|
import { SingleAutoCompleteConfiguration } from './single-auto-complete-configuration';
|
||||||
|
|
||||||
|
@Component({
|
||||||
|
selector: 'app-single-auto-complete',
|
||||||
|
templateUrl: './single-auto-complete.component.html',
|
||||||
|
styleUrls: ['./single-auto-complete.component.scss']
|
||||||
|
})
|
||||||
|
export class SingleAutoCompleteComponent implements OnInit {
|
||||||
|
|
||||||
|
@Input() reactiveFormControl: FormControl;
|
||||||
|
@Input() placeholder: string;
|
||||||
|
@Input() validationErrorString: string;
|
||||||
|
|
||||||
|
@Input() configuration: SingleAutoCompleteConfiguration;
|
||||||
|
|
||||||
|
// Selected Option Event
|
||||||
|
@Output() optionSelected: EventEmitter<any> = new EventEmitter();
|
||||||
|
|
||||||
|
private requestDelay = 200; //ms
|
||||||
|
private minFilteringChars = 3;
|
||||||
|
private loadDataOnStart = true;
|
||||||
|
|
||||||
|
// @Input() items: Observable<any[]>;
|
||||||
|
// @Input() filterFn?: (searchQuery: string) => Observable<any[]>;
|
||||||
|
// @Input() displayFn?: (item: any) => string;
|
||||||
|
// @Input() titleFn?: (item: any) => string;
|
||||||
|
// @Input() subtitleFn?: (item: any) => string;
|
||||||
|
loading = false;
|
||||||
|
_items: Observable<any[]>;
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
}
|
||||||
|
|
||||||
|
ngOnInit() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
filter(query: string): Observable<any[]> {
|
||||||
|
// If loadDataOnStart is enabled and query is empty we return the initial items.
|
||||||
|
if (this.isNullOrEmpty(query) && this.loadDataOnStart) {
|
||||||
|
return this.configuration.items || Observable.of([]);
|
||||||
|
} else if (query && query.length >= this.minFilteringChars) {
|
||||||
|
if (this.configuration.filterFn) {
|
||||||
|
return this.configuration.filterFn(query);
|
||||||
|
} else {
|
||||||
|
return this.configuration.items || Observable.of([]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return Observable.of([]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
isNullOrEmpty(query: string): boolean {
|
||||||
|
return typeof query !== 'string' || query === null || query.length === 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
_displayFn(item: any): string {
|
||||||
|
if (this.configuration.displayFn && item) { return this.configuration.displayFn(item); }
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
_titleFn(item: any): string {
|
||||||
|
if (this.configuration.titleFn && item) { return this.configuration.titleFn(item); }
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
_subtitleFn(item: any): string {
|
||||||
|
if (this.configuration.subtitleFn && item) { return this.configuration.subtitleFn(item); }
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
_requestDelay(): number {
|
||||||
|
return this.configuration.requestDelay || this.requestDelay;
|
||||||
|
}
|
||||||
|
|
||||||
|
_minFilteringChars(): number {
|
||||||
|
return this.configuration.minFilteringChars || this.minFilteringChars;
|
||||||
|
}
|
||||||
|
|
||||||
|
_loadDataOnStart(): boolean {
|
||||||
|
return this.configuration.loadDataOnStart || this.loadDataOnStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
_optionSelected(event: MatAutocompleteSelectedEvent) {
|
||||||
|
this.optionSelected.emit(event.option.value);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onInputFocus() {
|
||||||
|
// We set the items observable on focus to avoid the request being executed on component load.
|
||||||
|
if (!this._items) {
|
||||||
|
this._items = this.reactiveFormControl.valueChanges
|
||||||
|
.startWith(null)
|
||||||
|
.debounceTime(this.requestDelay)
|
||||||
|
.distinctUntilChanged()
|
||||||
|
.do(() => { this.loading = true; })
|
||||||
|
.flatMap(query => {
|
||||||
|
// If its a valid object, a selection just made and the object is set as the value of the form control. That means we should fire an extra request to the server.
|
||||||
|
if (this._isValidObject(query)) { return Observable.of([]); }
|
||||||
|
return this.filter(query);
|
||||||
|
})
|
||||||
|
.do(() => { this.loading = false; });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_isValidObject(value: any): boolean {
|
||||||
|
try {
|
||||||
|
if (!value) { return false; }
|
||||||
|
if (typeof value !== 'object') { JSON.parse(value); }
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
import { Component, OnInit, Input, ContentChild, TemplateRef, ViewChild, Output, EventEmitter } from "@angular/core";
|
import { Component, OnInit, Input, ContentChild, TemplateRef, ViewChild, Output, EventEmitter } from "@angular/core";
|
||||||
import { AutoCompleteConfiguration } from "../../autocomplete/AutoCompleteConfiguration";
|
|
||||||
import { FormGroup, FormControl, FormArray, AbstractControl } from "@angular/forms";
|
import { FormGroup, FormControl, FormArray, AbstractControl } from "@angular/forms";
|
||||||
import { ExternalSourcesUrlModel } from "../../../../models/external-sources/ExternalSourcesUrlModel";
|
import { ExternalSourcesUrlModel } from "../../../../models/external-sources/ExternalSourcesUrlModel";
|
||||||
|
import { AutoCompleteConfiguration } from "../../auto-complete/AutoCompleteConfiguration";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-external-item-listing',
|
selector: 'app-external-item-listing',
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
|
import { Component, OnInit, Input, Output, EventEmitter } from "@angular/core";
|
||||||
import { Placeholder } from "@angular/compiler/src/i18n/i18n_ast";
|
import { Placeholder } from "@angular/compiler/src/i18n/i18n_ast";
|
||||||
import { AutoCompleteConfiguration } from "../../autocomplete/AutoCompleteConfiguration";
|
|
||||||
import { FormGroup, FormControl } from "@angular/forms";
|
import { FormGroup, FormControl } from "@angular/forms";
|
||||||
|
import { AutoCompleteConfiguration } from "../../auto-complete/AutoCompleteConfiguration";
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-external-item',
|
selector: 'app-external-item',
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
import { BaseCriteriaComponent } from './components/criteria/base/base-criteria.component';
|
import { BaseCriteriaComponent } from './components/criteria/base/base-criteria.component';
|
||||||
import { FigurecardComponent } from './components/figurecard/figurecard.component';
|
import { FigurecardComponent } from './components/figurecard/figurecard.component';
|
||||||
import { AutocompleteComponent } from './components/autocomplete/autocomplete.component';
|
|
||||||
import { CommonModule } from '@angular/common';
|
import { CommonModule } from '@angular/common';
|
||||||
import { FlexLayoutModule } from '@angular/flex-layout';
|
import { FlexLayoutModule } from '@angular/flex-layout';
|
||||||
|
|
||||||
|
@ -22,6 +21,8 @@ import { AutoCompleteComponent } from './components/auto-complete/auto-complete.
|
||||||
import { ExternalItemListingComponent } from './components/external-items/external-item-listing/external-item-listing.component';
|
import { ExternalItemListingComponent } from './components/external-items/external-item-listing/external-item-listing.component';
|
||||||
import { ExternalItemComponent } from './components/external-items/external-item/external-item.component';
|
import { ExternalItemComponent } from './components/external-items/external-item/external-item.component';
|
||||||
import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
|
import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.component';
|
||||||
|
import { SingleAutoCompleteComponent } from './components/autocompletes/single/single-auto-complete.component';
|
||||||
|
import { MultipleAutoCompleteComponent } from './components/autocompletes/multiple/multiple-auto-complete.component';
|
||||||
|
|
||||||
@NgModule({
|
@NgModule({
|
||||||
imports: [
|
imports: [
|
||||||
|
@ -41,7 +42,6 @@ import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.componen
|
||||||
DatasetCriteriaComponent,
|
DatasetCriteriaComponent,
|
||||||
DataManagementPlanCriteriaComponent,
|
DataManagementPlanCriteriaComponent,
|
||||||
DataManagementPlanProfileCriteriaComponent,
|
DataManagementPlanProfileCriteriaComponent,
|
||||||
AutocompleteComponent,
|
|
||||||
FigurecardComponent,
|
FigurecardComponent,
|
||||||
BaseCriteriaComponent,
|
BaseCriteriaComponent,
|
||||||
FileUploaderComponent,
|
FileUploaderComponent,
|
||||||
|
@ -50,8 +50,9 @@ import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.componen
|
||||||
AutoCompleteComponent,
|
AutoCompleteComponent,
|
||||||
ExternalItemListingComponent,
|
ExternalItemListingComponent,
|
||||||
ExternalItemComponent,
|
ExternalItemComponent,
|
||||||
BreadcrumbComponent
|
BreadcrumbComponent,
|
||||||
|
SingleAutoCompleteComponent,
|
||||||
|
MultipleAutoCompleteComponent
|
||||||
],
|
],
|
||||||
|
|
||||||
exports: [
|
exports: [
|
||||||
|
@ -64,16 +65,17 @@ import { BreadcrumbComponent } from './components/breadcrumb/breadcrumb.componen
|
||||||
DatasetCriteriaComponent,
|
DatasetCriteriaComponent,
|
||||||
DataManagementPlanProfileCriteriaComponent,
|
DataManagementPlanProfileCriteriaComponent,
|
||||||
DataManagementPlanCriteriaComponent,
|
DataManagementPlanCriteriaComponent,
|
||||||
AutocompleteComponent,
|
|
||||||
FigurecardComponent,
|
FigurecardComponent,
|
||||||
BaseCriteriaComponent,
|
BaseCriteriaComponent,
|
||||||
FileUploaderComponent,
|
FileUploaderComponent,
|
||||||
UrlListingComponent,
|
UrlListingComponent,
|
||||||
NgForLimitPipe,
|
NgForLimitPipe,
|
||||||
AutoCompleteComponent,
|
AutoCompleteComponent,
|
||||||
ExternalItemListingComponent,
|
ExternalItemListingComponent,
|
||||||
ExternalItemComponent,
|
ExternalItemComponent,
|
||||||
BreadcrumbComponent
|
BreadcrumbComponent,
|
||||||
|
SingleAutoCompleteComponent,
|
||||||
|
MultipleAutoCompleteComponent
|
||||||
],
|
],
|
||||||
entryComponents: [
|
entryComponents: [
|
||||||
]
|
]
|
||||||
|
|
|
@ -134,7 +134,7 @@
|
||||||
"EDIT": "Edit"
|
"EDIT": "Edit"
|
||||||
},
|
},
|
||||||
"FIELDS": {
|
"FIELDS": {
|
||||||
"LABEL": "Label",
|
"LABEL": "Title",
|
||||||
"ABBREVIATION": "Abbreviation",
|
"ABBREVIATION": "Abbreviation",
|
||||||
"URI": "URL",
|
"URI": "URL",
|
||||||
"START": "Start",
|
"START": "Start",
|
||||||
|
|
Loading…
Reference in New Issue