diff --git a/projects/igniteui-angular/src/lib/select/select.component.spec.ts b/projects/igniteui-angular/src/lib/select/select.component.spec.ts index 1fbb60cdfb8..76a525181e9 100644 --- a/projects/igniteui-angular/src/lib/select/select.component.spec.ts +++ b/projects/igniteui-angular/src/lib/select/select.component.spec.ts @@ -424,6 +424,7 @@ describe('igxSelect', () => { expect(inputElement.nativeElement.getAttribute('aria-haspopup')).toEqual('listbox'); expect(inputElement.nativeElement.getAttribute('aria-labelledby')).toEqual(labelID); expect(dropdownListElement.nativeElement.getAttribute('aria-labelledby')).toEqual(labelID); + expect(inputElement.nativeElement.getAttribute('aria-required')).toEqual('false'); expect(inputElement.nativeElement.getAttribute('aria-owns')).toEqual(select.listId); expect(inputElement.nativeElement.getAttribute('aria-expanded')).toEqual('false'); expect(toggleBtn.nativeElement.getAttribute('aria-hidden')).toEqual('true'); @@ -574,6 +575,7 @@ describe('igxSelect', () => { const dom = fix.debugElement; const selectComp = fix.componentInstance.select; const formGroup: UntypedFormGroup = fix.componentInstance.reactiveForm; + inputElement = dom.query(By.css('.' + CSS_CLASS_INPUT)); let inputGroupIsRequiredClass = dom.query(By.css('.' + CSS_CLASS_INPUT_GROUP_REQUIRED)); let inputGroupInvalidClass = dom.query(By.css('.' + CSS_CLASS_INPUT_GROUP_INVALID)); // interaction test - expect actual asterisk @@ -583,6 +585,7 @@ describe('igxSelect', () => { expect(asterisk).toBe('"*"'); expect(inputGroupIsRequiredClass).toBeDefined(); expect(inputGroupIsRequiredClass).not.toBeNull(); + expect(inputElement.nativeElement.getAttribute('aria-required')).toEqual('true'); // 2) check that input group's --invalid class is NOT applied expect(inputGroupInvalidClass).toBeNull(); @@ -604,11 +607,13 @@ describe('igxSelect', () => { inputGroupIsRequiredClass = dom.query(By.css('.' + CSS_CLASS_INPUT_GROUP_REQUIRED)); expect(inputGroupIsRequiredClass).not.toBeNull(); expect(inputGroupIsRequiredClass).not.toBeUndefined(); + expect(inputElement.nativeElement.getAttribute('aria-required')).toEqual('true'); // 3) Check if the input group's --invalid and --required classes are removed when validator is dynamically cleared fix.componentInstance.removeValidators(formGroup); fix.detectChanges(); tick(); + expect(inputElement.nativeElement.getAttribute('aria-required')).toEqual('false'); inputGroupIsRequiredClass = dom.query(By.css('.' + CSS_CLASS_INPUT_GROUP_REQUIRED)); const selectFormReference = fix.componentInstance.reactiveForm.controls.optionsSelect; @@ -642,6 +647,7 @@ describe('igxSelect', () => { // Re-add all Validators fix.componentInstance.addValidators(formGroup); fix.detectChanges(); + expect(inputElement.nativeElement.getAttribute('aria-required')).toEqual('true'); inputGroupIsRequiredClass = dom.query(By.css('.' + CSS_CLASS_INPUT_GROUP_REQUIRED)); expect(inputGroupIsRequiredClass).toBeDefined(); @@ -650,24 +656,6 @@ describe('igxSelect', () => { // interaction test - expect actual asterisk asterisk = window.getComputedStyle(dom.query(By.css('.' + CSS_CLASS_INPUT_GROUP_LABEL)).nativeElement, ':after').content; expect(asterisk).toBe('"*"'); - - // 4) Should NOT remove asterisk, when remove validators on igxSelect with required HTML attribute set(edge case) - // set required HTML attribute - inputGroup.parent.nativeElement.setAttribute('required', ''); - // Re-add all Validators - fix.componentInstance.addValidators(formGroup); - fix.detectChanges(); - // update and clear validators - fix.componentInstance.removeValidators(formGroup); - fix.detectChanges(); - tick(); - // expect asterisk - asterisk = window.getComputedStyle(dom.query(By.css('.' + CSS_CLASS_INPUT_GROUP_LABEL)).nativeElement, ':after').content; - expect(asterisk).toBe('"*"'); - inputGroupIsRequiredClass = dom.query(By.css('.' + CSS_CLASS_INPUT_GROUP_REQUIRED)); - expect(inputGroupIsRequiredClass).toBeDefined(); - expect(inputGroupIsRequiredClass).not.toBeNull(); - expect(inputGroupIsRequiredClass).not.toBeUndefined(); })); it('should update validity state when programmatically setting errors on reactive form controls', fakeAsync(() => { diff --git a/projects/igniteui-angular/src/lib/select/select.component.ts b/projects/igniteui-angular/src/lib/select/select.component.ts index d448e4fe6dc..c9307d29884 100644 --- a/projects/igniteui-angular/src/lib/select/select.component.ts +++ b/projects/igniteui-angular/src/lib/select/select.component.ts @@ -606,19 +606,25 @@ export class IgxSelectComponent extends IgxDropDownComponent implements IgxSelec protected manageRequiredAsterisk(): void { const hasRequiredHTMLAttribute = this.elementRef.nativeElement.hasAttribute('required'); + let isRequired = false; + if (this.ngControl && this.ngControl.control.validator) { - // Run the validation with empty object to check if required is enabled. const error = this.ngControl.control.validator({} as AbstractControl); - this.inputGroup.isRequired = error && error.required; - this.cdr.markForCheck(); + isRequired = !!(error && error.required); + } + + this.inputGroup.isRequired = isRequired; - // If validator is dynamically cleared and no required HTML attribute is set, - // reset label's required class(asterisk) and IgxInputState #6896 - } else if (this.inputGroup.isRequired && this.ngControl && !this.ngControl.control.validator && !hasRequiredHTMLAttribute) { + if (this.input?.nativeElement) { + this.input.nativeElement.setAttribute('aria-required', isRequired.toString()); + } + + // Handle validator removal case + if (!isRequired && !hasRequiredHTMLAttribute) { this.input.valid = IgxInputState.INITIAL; - this.inputGroup.isRequired = false; - this.cdr.markForCheck(); } + + this.cdr.markForCheck(); } private setSelection(item: IgxDropDownItemBaseDirective) {