diff --git a/src/app/access-control/group-registry/group-form/group-form.component.ts b/src/app/access-control/group-registry/group-form/group-form.component.ts index b2b9fab58d..072fdda063 100644 --- a/src/app/access-control/group-registry/group-form/group-form.component.ts +++ b/src/app/access-control/group-registry/group-form/group-form.component.ts @@ -1,4 +1,4 @@ -import { Component, EventEmitter, HostListener, OnDestroy, OnInit, Output } from '@angular/core'; +import { Component, EventEmitter, HostListener, OnDestroy, OnInit, Output, ChangeDetectorRef } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { ActivatedRoute, Router } from '@angular/router'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; @@ -16,7 +16,7 @@ import { of as observableOf, Subscription, } from 'rxjs'; -import { catchError, map, switchMap, take, filter } from 'rxjs/operators'; +import { catchError, map, switchMap, take, filter, debounceTime } from 'rxjs/operators'; import { getCollectionEditRolesRoute } from '../../../collection-page/collection-page-routing-paths'; import { getCommunityEditRolesRoute } from '../../../community-page/community-page-routing-paths'; import { DSpaceObjectDataService } from '../../../core/data/dspace-object-data.service'; @@ -45,6 +45,7 @@ import { NotificationsService } from '../../../shared/notifications/notification import { followLink } from '../../../shared/utils/follow-link-config.model'; import { NoContent } from '../../../core/shared/NoContent.model'; import { Operation } from 'fast-json-patch'; +import { ValidateGroupExists } from './validators/group-exists.validator'; @Component({ selector: 'ds-group-form', @@ -126,6 +127,12 @@ export class GroupFormComponent implements OnInit, OnDestroy { */ public AlertTypeEnum = AlertType; + /** + * Subscription to email field value change + */ + groupNameValueChangeSubscribe: Subscription; + + constructor(public groupDataService: GroupDataService, private ePersonDataService: EPersonDataService, private dSpaceObjectDataService: DSpaceObjectDataService, @@ -136,7 +143,8 @@ export class GroupFormComponent implements OnInit, OnDestroy { protected router: Router, private authorizationService: AuthorizationDataService, private modalService: NgbModal, - public requestService: RequestService) { + public requestService: RequestService, + protected changeDetectorRef: ChangeDetectorRef) { } ngOnInit() { @@ -192,6 +200,14 @@ export class GroupFormComponent implements OnInit, OnDestroy { this.groupDescription, ]; this.formGroup = this.formBuilderService.createFormGroup(this.formModel); + + if (!!this.formGroup.controls.groupName && !this.formGroup.controls.groupName.value) { + this.formGroup.controls.groupName.setAsyncValidators(ValidateGroupExists.createValidator(this.groupDataService)); + this.groupNameValueChangeSubscribe = this.groupName.valueChanges.pipe(debounceTime(300)).subscribe(() => { + this.changeDetectorRef.detectChanges(); + }); + } + this.subs.push( observableCombineLatest( this.groupDataService.getActiveGroup(), diff --git a/src/app/access-control/group-registry/group-form/validators/group-exists.validator.ts b/src/app/access-control/group-registry/group-form/validators/group-exists.validator.ts new file mode 100644 index 0000000000..90553fbc76 --- /dev/null +++ b/src/app/access-control/group-registry/group-form/validators/group-exists.validator.ts @@ -0,0 +1,34 @@ +import { AbstractControl, ValidationErrors } from '@angular/forms'; +import { Observable } from 'rxjs'; +import { map, filter } from 'rxjs/operators'; + +import { buildPaginatedList, PaginatedList } from '../../../../core/data/paginated-list.model'; +import { GroupDataService } from '../../../../core/eperson/group-data.service'; +import { getFirstSucceededRemoteData,getFirstSucceededRemoteListPayload } from '../../../../core/shared/operators'; +import { Group } from '../../../../core/eperson/models/group.model'; + +export class ValidateGroupExists { + + /** + * This method will create the validator with the groupDataService requested from component + * @param groupDataService the service with DI in the component that this validator is being utilized. + * @return Observable + */ + static createValidator(groupDataService: GroupDataService) { + return (control: AbstractControl): Promise | Observable => { + return groupDataService.searchGroups(control.value, { + currentPage: 1, + elementsPerPage: 100 + }) + .pipe( + getFirstSucceededRemoteListPayload(), + map( (groups: Group[]) => { + return groups.filter(group => group.name === control.value); + }), + map( (groups: Group[]) => { + return groups.length > 0 ? { groupExists: true } : null; + }), + ); + }; + } +} diff --git a/src/assets/i18n/en.json5 b/src/assets/i18n/en.json5 index 5cd42bc24c..081f48df3e 100644 --- a/src/assets/i18n/en.json5 +++ b/src/assets/i18n/en.json5 @@ -1351,6 +1351,8 @@ "error.validation.emailTaken": "This E-mail is already taken", + "error.validation.groupExists": "This group already exists", + "file-section.error.header": "Error obtaining files for this item",