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 5, 2023
1 parent 2bc70bd commit 9625c34
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 6 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 @@ -101,7 +101,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 +645,35 @@ 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('controlChangeEmitter: should emit change with input value if input value changes', fakeAsync((): void => {
const inputValue = 'value';

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,21 @@ export abstract class PoInputGeneric extends PoInputBaseComponent implements Aft
super(cd);

this.el = el;

effect(() => {
if (!this.required) {
this.validateClassesForMask();
}
});
}

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

Expand All @@ -43,6 +60,8 @@ export abstract class PoInputGeneric extends PoInputBaseComponent implements Aft

ngAfterViewInit() {
this.afterViewInit();

this.validateClassesForMask();
}

afterViewInit() {
Expand Down Expand Up @@ -166,6 +185,18 @@ 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 {
element.classList.remove('ng-invalid');
}
}

verifyPattern(pattern: string, value: any) {
return new RegExp(pattern).test(value);
}
Expand Down
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
62 changes: 62 additions & 0 deletions projects/ui/src/lib/components/po-field/po-input/po-mask.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -529,6 +529,61 @@ describe('PoMask', () => {
expect(fakeEvent.target.selectionStart).toBe(3);
});

it('should return true where mask is valid', () => {
const fakeThis = mask;
fakeThis.mask = '(99)99';

fakeEvent.target.value = '(99)99';

const response = fakeThis.checkMaskRegex(fakeEvent.target.value, fakeThis.mask);

expect(response).toBe(true);
});

it('should return false where mask is invalid', () => {
const fakeThis = mask;
fakeThis.mask = '(99)99';

fakeEvent.target.value = '(aa)bb';

const response = fakeThis.checkMaskRegex(fakeEvent.target.value, fakeThis.mask);

expect(response).toBe(false);
});

it('should return false where mask for different lenghts', () => {
const fakeThis = mask;
fakeThis.mask = '(99)99';

fakeEvent.target.value = '(21)';

const response = fakeThis.checkMaskRegex(fakeEvent.target.value, fakeThis.mask);

expect(response).toBe(false);
});

it('should return false where input is empty', () => {
const fakeThis = mask;
fakeThis.mask = '(99)99';

fakeEvent.target.value = '';

const response = fakeThis.checkMaskRegex(fakeEvent.target.value, fakeThis.mask);

expect(response).toBe(false);
});

it('should return false where input is mask', () => {
const fakeThis = mask;
fakeThis.mask = '99-99';

fakeEvent.target.value = '12A34';

const response = fakeThis.checkMaskRegex(fakeEvent.target.value, fakeThis.mask);

expect(response).toBe(true);
});

it('should return when keydown (ctrl+V) ', () => {
const fakeThis = {
mask: '(99)99'
Expand Down Expand Up @@ -651,6 +706,13 @@ describe('PoMask', () => {
expect(mask.valueToModel).toBe('1-1-1');
});

it('should return value "" to model and validMask return false', () => {
mask.formatModel = true;
mask.formatValue('', '9-9-9');
expect(mask.valueToModel).toBe('');
expect(mask.validMask()).toBe(false);
});

it('should test replaceMask function', () => {
expect(mask.replaceMask('0')).toEqual(/[0]/);
expect(mask.replaceMask('1')).toEqual(/[0-1]/);
Expand Down
27 changes: 27 additions & 0 deletions projects/ui/src/lib/components/po-field/po-input/po-mask.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { signal } from '@angular/core';

/**
* Para usar o po-mask é preciso instanciar esta classe passando a máscara como
* primeiro parâmetro, e no segundo parâmetro, deve se informado true, caso queira
Expand All @@ -9,6 +11,7 @@ export class PoMask {
// controle de posição
initialPosition: number = 0;
finalPosition: number = 0;
validMask = signal<boolean>(false);

pattern: string = '';
get getPattern(): string {
Expand Down Expand Up @@ -352,8 +355,32 @@ export class PoMask {
this.valueToInput = valueProcessed;
this.valueToModel = this.removeFormattingValue(valueProcessed);
}


if(valueProcessed.length > 1) {
this.validMask.set(true);
} else {
this.validMask.set(false);
}

return valueProcessed;
}

checkMaskRegex(inputValue: string, mask: string) {
let returnMaskRegex = true;
if (inputValue.length !== mask.length) {
returnMaskRegex = false;
}

for (let i = 0; i < inputValue.length; i++) {
if (mask[i] === '9' && isNaN(parseInt(inputValue[i], 10))) {
returnMaskRegex = false;
}
}

return returnMaskRegex;
}

// verifica se tem algum caracter de mascara antes do cursor
checkMaskBefore($event: any, position: number) {
if (this.isFixedCharacterGuide($event.target.value.toString().charAt(this.initialPosition - 1))) {
Expand Down

0 comments on commit 9625c34

Please sign in to comment.