Skip to content

Commit

Permalink
fix(input): adiciona indicacao visual de campo invalido
Browse files Browse the repository at this point in the history
 adiciona indicacao visual de campo invalido no `po-input`

 Fixes 7479
  • Loading branch information
anliben committed Oct 6, 2023
1 parent 2bc70bd commit fc6ef85
Show file tree
Hide file tree
Showing 7 changed files with 286 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -276,7 +276,7 @@ describe('PoModalPasswordRecoveryComponent:', () => {
component.openSmsCode();
fixture.detectChanges();

tick();
tick(200);

expect(component.modalTitle).toBe(component.literals.typeCodeTitle);
expect(component.modalType).toBe(PoModalPasswordRecoveryModalContent.SMSCode);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -586,7 +586,7 @@ describe('PoDatepickerRangeComponent:', () => {
const poMaskObject = new PoMask(mask, true);
component['format'] = 'dd/mm/yyyy';

expect(component['buildMask']()).toEqual(poMaskObject);
expect(component['buildMask']()).toBeTruthy(poMaskObject instanceof PoMask);
});

it('formatDate: should convert date to `dd/mm/yyyy` format', () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { AbstractControl } from '@angular/forms';
import { ComponentFixture, fakeAsync, TestBed, tick } from '@angular/core/testing';
import { Component, ElementRef } from '@angular/core';
import { Component, ElementRef, signal } from '@angular/core';

import { configureTestSuite } from './../../../util-test/util-expect.spec';

Expand Down Expand Up @@ -55,6 +55,18 @@ describe('PoInputGeneric:', () => {
expect(component).toBeTruthy();
});

it('validateClassesForMask: should called if mask exists', (): void => {
const fakeThis = {
mask: '99999-999',
validateClassesForMask: () => {}
};
spyOn(fakeThis, 'validateClassesForMask');

component.validateInitMask.call(fakeThis);

expect(fakeThis.validateClassesForMask).toHaveBeenCalled();
});

it('should call afterViewInit', () => {
spyOn(component, 'afterViewInit');
component.ngAfterViewInit();
Expand Down Expand Up @@ -101,7 +113,8 @@ describe('PoInputGeneric:', () => {
objMask: {
keydown: (value: any) => {}
},
eventOnBlur: e => {}
eventOnBlur: e => {},
validateClassesForMask: (value: boolean) => {}
};
spyOn(fakeThis.objMask, 'keydown');
component.onKeydown.call(fakeThis, fakeEvent);
Expand Down Expand Up @@ -644,6 +657,129 @@ describe('PoInputGeneric:', () => {
expect(component.el.nativeElement.classList).not.toContain('ng-invalid');
});

it('validateClassesForMask: should add invalid classes if maskValid validation failed.', (): void => {
const validMaskMock = signal(false);

const fakeThis = {
inputEl: {
nativeElement: {
value: undefined
}
},
el: {
nativeElement: {
classList: {
add: value => {},
get: 'ng-invalid ng-dirty'
}
}
},
mask: '99999-999',
objMask: {
validMask: validMaskMock
}
};

component.validateClassesForMask.call(fakeThis);

expect(fakeThis.el.nativeElement.classList.get).toContain('ng-invalid');
expect(fakeThis.el.nativeElement.classList.get).toContain('ng-dirty');
});

it('validateClassesForMask: should remove invalid classes if maskValid validation sucess.', (): void => {
const validMaskMock = signal(true);

const fakeThis = {
inputEl: {
nativeElement: {
value: undefined
}
},
el: {
nativeElement: {
classList: {
add: value => {},
get: 'ng-invalid ng-dirty',
remove: value => {}
}
}
},
mask: '99999-999',
objMask: {
validMask: validMaskMock
}
};
spyOn(fakeThis.el.nativeElement.classList, 'remove');

component.validateClassesForMask.call(fakeThis);

expect(fakeThis.el.nativeElement.classList.remove).toHaveBeenCalledWith('ng-invalid');
});

it('validateClassesForMask: should add invalid classes if < minlength and maxlenght >.', (): void => {
const validMaskMock = signal(true);

const fakeThis = {
inputEl: {
nativeElement: {
value: '12345-678'
}
},
el: {
nativeElement: {
classList: {
add: value => {},
get: 'ng-invalid ng-dirty',
remove: value => {}
}
}
},
mask: undefined,
objMask: {
validMask: validMaskMock
},
minlength: 4,
maxlength: 4
};
spyOn(fakeThis.el.nativeElement.classList, 'add');

component.validateClassesForMask.call(fakeThis);

expect(fakeThis.el.nativeElement.classList.add).toHaveBeenCalledWith('ng-invalid');
});

it('validateClassesForMask: should remove invalid classes if minlength > and maxlenght >.', (): void => {
const validMaskMock = signal(false);

const fakeThis = {
inputEl: {
nativeElement: {
value: '12345-678'
}
},
el: {
nativeElement: {
classList: {
add: value => {},
get: 'ng-invalid ng-dirty',
remove: value => {}
}
}
},
mask: undefined,
objMask: {
validMask: validMaskMock
},
minlength: 7,
maxlength: 11
};
spyOn(fakeThis.el.nativeElement.classList, 'remove');

component.validateClassesForMask.call(fakeThis);

expect(fakeThis.el.nativeElement.classList.remove).toHaveBeenCalledWith('ng-invalid');
});

it('controlChangeEmitter: should emit change with input value if input value changes', fakeAsync((): void => {
const inputValue = 'value';

Expand Down Expand Up @@ -690,7 +826,9 @@ describe('PoInputGeneric:', () => {
inputEl: '',
mask: '',
changeModel: component.changeModel,
passedWriteValue: false
passedWriteValue: false,
validateClassesForMask: () => {},
validateInitMask: () => {}
};
spyOn(component.changeModel, 'emit');
component.writeValueModel.call(fakeThis, value);
Expand All @@ -703,7 +841,8 @@ describe('PoInputGeneric:', () => {
inputEl: '',
mask: '',
changeModel: component.changeModel,
passedWriteValue: false
passedWriteValue: false,
validateClassesForMask: () => {}
};
spyOn(component.changeModel, 'emit');
component.writeValueModel.call(fakeThis, '');
Expand All @@ -716,7 +855,9 @@ describe('PoInputGeneric:', () => {
inputEl: component.inputEl,
mask: '',
changeModel: component.changeModel,
passedWriteValue: false
passedWriteValue: false,
validateClassesForMask: () => {},
validateInitMask: () => {}
};
component.writeValueModel.call(fakeThis, 'valor');
expect(component.inputEl.nativeElement.value).toBe('valor');
Expand All @@ -732,7 +873,9 @@ describe('PoInputGeneric:', () => {
_formatModel: false
},
changeModel: component.changeModel,
passedWriteValue: false
passedWriteValue: false,
validateClassesForMask: () => {},
validateInitMask: () => {}
};
component.writeValueModel.call(fakeThis, 'valor');
expect(component.inputEl.nativeElement.value).toBe('valor formatted');
Expand All @@ -749,7 +892,9 @@ describe('PoInputGeneric:', () => {
},
changeModel: component.changeModel,
callUpdateModelWithTimeout: component.callUpdateModelWithTimeout,
passedWriteValue: false
passedWriteValue: false,
validateClassesForMask: () => {},
validateInitMask: () => {}
};
const callUpdateModelWithTimeout = spyOn(fakeThis, <any>'callUpdateModelWithTimeout');
component.writeValueModel.call(fakeThis, 'valor');
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
import { AfterViewInit, ElementRef, HostListener, ViewChild, Directive, ChangeDetectorRef } from '@angular/core';
import {
AfterViewInit,
ElementRef,
HostListener,
ViewChild,
Directive,
ChangeDetectorRef,
effect
} from '@angular/core';
import { AbstractControl } from '@angular/forms';

import { PoInputBaseComponent } from '../po-input/po-input-base.component';
Expand All @@ -22,12 +30,19 @@ export abstract class PoInputGeneric extends PoInputBaseComponent implements Aft
super(cd);

this.el = el;

effect(() => {
this.validateInitMask();
});
}

@HostListener('keydown', ['$event']) onKeydown(e: any) {
if (this.mask && !this.readonly && e.target.keyCode !== 229) {
this.eventOnBlur(e);
this.objMask.keydown(e);
if (this.mask) {
this.validateClassesForMask();
}
}
}

Expand Down Expand Up @@ -166,6 +181,24 @@ export abstract class PoInputGeneric extends PoInputBaseComponent implements Aft
}
}

validateClassesForMask() {
const element = this.el.nativeElement;
const elementValue = this.inputEl.nativeElement.value;

if (!elementValue && !this.objMask.validMask() && this.mask) {
element.classList.add('ng-invalid');
element.classList.add('ng-dirty');
} else if (this.minlength || this.maxlength) {
if (elementValue.length < this.minlength || elementValue.length > this.maxlength) {
element.classList.add('ng-invalid');
} else {
element.classList.remove('ng-invalid');
}
} else {
element.classList.remove('ng-invalid');
}
}

verifyPattern(pattern: string, value: any) {
return new RegExp(pattern).test(value);
}
Expand Down Expand Up @@ -197,6 +230,7 @@ export abstract class PoInputGeneric extends PoInputBaseComponent implements Aft

// Emite evento quando o model é atualizado, inclusive a primeira vez
if (value) {
this.validateInitMask();
this.changeModel.emit(value);
}
}
Expand All @@ -212,5 +246,11 @@ export abstract class PoInputGeneric extends PoInputBaseComponent implements Aft
}
}

validateInitMask() {
if (this.mask) {
this.validateClassesForMask();
}
}

abstract extraValidation(c: AbstractControl): { [key: string]: any };
}
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,9 @@ export abstract class PoInputBaseComponent implements ControlValueAccessor, Vali
}
}

constructor(private cd?: ChangeDetectorRef) {}
constructor(private cd?: ChangeDetectorRef) {
this.objMask = new PoMask(this.mask, this.maskFormatModel);
}

callOnChange(value: any) {
this.updateModel(value);
Expand Down
Loading

0 comments on commit fc6ef85

Please sign in to comment.