Skip to content

Instantly share code, notes, and snippets.

@odahcam
Last active March 9, 2021 15:41
Show Gist options
  • Star 11 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save odahcam/fe8c477eccb737b533eec0687982b340 to your computer and use it in GitHub Desktop.
Save odahcam/fe8c477eccb737b533eec0687982b340 to your computer and use it in GitHub Desktop.
Validação de CPF e CNPJ com integração com React Forms, implementado com Angular 6.

Exemplos

Uso com reactive forms

new FormGroup({
    cpfManualLength: new FormControl('', [
        Validators.required,
        Validators.pattern(/^(\d{3}\.){2}\d{3}\-\d{2}$/),
        Validators.minLength(14), // digits + word characters
        Validators.maxLength(14), // digits + word characters
        CpfCnpjValidator.validate,
    ]),
    cpf: new FormControl('', [
        Validators.required,
        Validators.pattern(/^(\d{3}\.){2}\d{3}\-\d{2}$/),       
        CpfCnpjValidator.validateCpf,
    ]),
    cnpj: new FormControl('', [
        Validators.required,
        // @todo add CNPJ pattern
        CpfCnpjValidator.validateCnpj,
    ]),
});

Uso com template driven forms

Inclua a directive CpfCnpjValidatorDirective no módulo onde você deseja utilizá-la e use +- como o seguinte:

<mat-form-field appearance="outline">

    <mat-label>CPF</mat-label>
    <input matInput name="cpf" type="tel" appCpfCnpjValidate length="14" [textMask]="maskCpfOptions" placeholder="000.000.000-00">

    <mat-hint align="start" *ngIf="formSignInGroup.get('cpf').invalid">xxx.xxx.xxx-xx</mat-hint>
    <mat-hint align="end">{{ getNumericCharsLength(formSignInGroup.get('cpf').value) }} / 11</mat-hint>

    <mat-error align="start" *ngIf="formSignInGroup.get('cpf').hasError('digit')">CPF inválido.</mat-error>

</mat-form-field>

Referências

import { Directive } from '@angular/core';
import { Validator, NG_VALIDATORS, AbstractControl, ValidationErrors } from '@angular/forms';
import { CpfCnpjValidator } from '@shared/cpf-cnpj.validator';
@Directive({
selector: '[appCpfCnpjValidate][ngModel]',
providers: [{
provide: NG_VALIDATORS,
useExisting: CpfCnpjValidatorDirective,
multi: true
}]
})
export class CpfCnpjValidatorDirective extends CpfCnpjValidator implements Validator {}
import { Component, OnDestroy } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material';
import { AlertDialogComponent } from '@shared/dialogs';
import { BehaviorSubject } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { SorteioResult } from '../state/sorteio-result.model';
import { SorteioService } from '../state/sorteio.service';
import { ActivityIndicatorOverlayService } from '@havan/activity-indicator-overlay';
import { CpfCnpjValidator } from '@shared/validators/cpf-cnpj.validator';
const maskTelefoneSm = ['(', /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/, /(\d)?/];
const maskTelefoneLg = ['(', /\d/, /\d/, ')', ' ', /\d/, /\d/, /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];
@Component({
selector: 'app-home',
templateUrl: './home.component.html',
styleUrls: ['./home.component.scss']
})
export class HomeComponent implements OnDestroy {
form: FormGroup;
textMaskTelefone$: BehaviorSubject<{ mask: (RegExp | string)[], guide: boolean }>;
textMaskCpf = {
mask: [/\d/, /\d/, /\d/, '.', /\d/, /\d/, /\d/, '.', /\d/, /\d/, /\d/, '-', /\d/, /\d/],
guide: false,
};
/**
*
*/
constructor(
private readonly _sorteio: SorteioService,
private readonly _dialog: MatDialog,
private readonly _aio: ActivityIndicatorOverlayService,
) {
const cpfValidators = [
Validators.required,
Validators.pattern(/^(\d{3}\.){2}\d{3}\-\d{2}$/),
CpfCnpjValidator.validateCpf
];
const cpfField = new FormControl(null, cpfValidators);
const nomeField = new FormControl(null, Validators.required);
const emailField = new FormControl(null, Validators.email);
const telefoneField = new FormControl(null, Validators.required);
this.form = new FormGroup({ cpfField, nomeField, emailField, telefoneField });
this.textMaskTelefone$ = new BehaviorSubject({ mask: maskTelefoneSm, guide: false });
}
/**
* Lifecycle hook.
*/
ngOnDestroy(): void {
// this._subs.unsubscribe();
}
onSubmitForm(): void {
if (!this.form.valid) {
this._dialog.open(AlertDialogComponent, {
data: {
content: 'Formulario invalido'
}
});
}
this._aio.open();
const formData = this.form.value;
const data = {
cpf: formData.cpfField,
email: formData.emailField,
telefone: formData.telefoneField,
nome: formData.nomeField,
};
this._sorteio.participar(data)
.pipe(finalize(() => this._aio.close()))
.subscribe(
resposta => this._dialogSorteioSuccess(resposta),
err => this._dialogSorteioError(err),
);
}
onTelefonePress(value: string) {
this._nextTelefoneMask((value || '').replace(/\D/g, '').length);
}
private _dialogSorteioError(err: SorteioResult): void {
if (!err.Mensagem) { return; }
this._dialog.open(AlertDialogComponent, {
data: {
content: err.Mensagem,
}
});
}
private _dialogSorteioSuccess(resposta: SorteioResult): void {
this._dialog.open(AlertDialogComponent, { data: { content: resposta.Mensagem } });
}
private _nextTelefoneMask(telefoneLength: number): void {
const mask = this._getTelefoneMask(telefoneLength);
const guide = false;
this.textMaskTelefone$.next({ mask, guide });
}
private _getTelefoneMask(telefoneLength: number): (RegExp | string)[] {
return telefoneLength < 10 ? maskTelefoneSm : maskTelefoneLg;
}
}
@9uilherme
Copy link

There is a problem in file cpf-cnpj.validator.ts, in line 19-23 i replaced for return digit < 2 ? 0 : CpfCnpjValidator.cpfLength - digit;

@odahcam
Copy link
Author

odahcam commented Jun 10, 2019

Thanks @9uilherme, the problem was that isCpf variable's value was wrongly defined.

@fbmarina
Copy link

CNPJ pattern:
Validators.pattern(/(^\d{2}.\d{3}.\d{3}/\d{4}-\d{2}$)/)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment