ExtJS 4 Form: Exemplo Campos CPF e CNPJ

02/08/2011 | By

Neste post vou mostrar como usar campos do tipo CPF ou CNPJ com validação em um Form do Ext JS 4.

Campos de CPF e CNPJ são bem comuns no uso de sistemas brasileiros. E sempre fazer aquele algoritmo de validação é um pouco chato. Existem 2 plugin/extensões do Ext JS 4 para facilitar a inserção desses campos em um form e ainda já faz a validação se o CPF ou CNPJ é válido.

extjs4 cpf cnpj loiane ExtJS 4 Form: Exemplo Campos CPF e CNPJ

Show me the code!

Campo CPF:

Ext.define('Ux.CpfField', {
   extend: 'Ext.form.field.Text',
   alias: ['widget.cpffield'],

   autocomplete: "off",
   soNumero: false,
   maxLength: (this.soNumero) ? 11 : 14,

   initComponent: function(){
      var me = this;

      Ext.apply(Ext.form.VTypes, {
         cpf: function(b, a) {
            return me.validacpf(b);
         },
         cpfText: "CPF inválido!"
      });

      Ext.apply(me, { vtype: 'cpf' });
      me.callParent();
   },
   initEvents: function() {
      var me = this;
      var el = me.inputEl;

      el.on("keydown", me.stopEventFunction, me);
      el.on("keyup", me.formatCPF, me);
      el.on("keypress", me.stopEventFunction, me);
      el.on("focus", me.startCPF, me);
      el.on("blur", me.clearCPF, me);

      me.callParent();
   },
   KEY_RANGES: {
      numeric: [48, 57],
      padnum: [96, 105]
   },
   isInRange: function(a, b) {
      return a >= b[0] && a <= b[1];
   },
   stopEventFunction: function(a) {
      var me = this;

      var b = a.getKey();
      if (me.isInRange(b, me.KEY_RANGES.padnum)) {
         b -= 48;
      }
      if (((b >= 41 && b <= 122) || b == 32 || b == 8 || b > 186) && (!a.altKey && !a.ctrlKey)) {
         a.stopEvent();
      }
   },
   startCPF: function() {
      var me = this;
      var a = me.inputEl.dom;

      if (a.value == "") {
         a.value = "";
         if (me.soNumero) {
            a.value = "00000000000";
         } else {
            a.value = "000.000.000-00";
         }
      }
   },
   clearCPF: function() {
      var me = this;
      var a = me.inputEl.dom;
      if (a.value == "000.000.000-00" || a.value == "00000000000"){
         a.value = "";
         me.validate();
      }
   },
   formatCPF: function(k) {
      var me = this;
      var j = k.getKey();
      if (me.isInRange(j, me.KEY_RANGES.padnum)) {
         j -= 48;
      }
      var d = (me.isInRange(j, me.KEY_RANGES.numeric) ? String.fromCharCode(j) : "");
      var e = me.inputEl.dom;
      var h = (e.value.replace(/\D/g, "").substr(1) + d).replace(/\D/g, "");
      var a = h.length;
      if (d == "" && a > 0 && j == 8) {
         a--;
         h = h.substr(0, a);
         k.stopEvent();
      }
      if (e.maxLength + 1 && a >= e.maxLength) {
         return false;
      }
      if (a < 11) {
         var b = "";
         for (var c = 0; c < 11 - a; c++) {
            b = b + "0";
         }
         h = b + h;
         a = 11;
      }
      if (me.soNumero) {
         e.value = h;
      } else {
         var l = "";
         l = h.substr(0, 3) + "." + h.substr(3, 3) + "." + h.substr(6, 3) + "-" + h.substr(9);
         e.value = l;
      }
   },
   validacpf: function(e) {
      if (e == "")
         return true;
      var b;
      s = e.replace(/\D/g, "");
      if (parseInt(s, 10) == 0) {
         return false;
      }

      var iguais = true;
      for (i = 0; i < s.length - 1; i++){
         if (s.charAt(i) != s.charAt(i + 1)){
            iguais = false;
         }
      }

      if (iguais)
         return false;

      var h = s.substr(0, 9);
      var a = s.substr(9, 2);
      var d = 0;
      for (b = 0; b < 9; b++) {
         d += h.charAt(b) * (10 - b);
      }
      if (d == 0) {
         return false;
      }
      d = 11 - (d % 11);
      if (d > 9) {
         d = 0;
      }
      if (a.charAt(0) != d) {
         return false;
      }
      d *= 2;
      for (b = 0; b < 9; b++) {
         d += h.charAt(b) * (11 - b);
      }
      d = 11 - (d % 11);
      if (d > 9) {
         d = 0;
      }
      if (a.charAt(1) != d) {
         return false;
      }
      return true;
   }
});

Campo CNPJ:

Ext.define('Ux.CnpjField', {
   extend: 'Ext.form.field.Text',
   alias: ['widget.cnpjfield'],

   autocomplete: "off",
   soNumero: false,
   maxLength: (this.soNumero) ? 15 : 19,

   initComponent: function(){
      var me = this;

      Ext.apply(Ext.form.VTypes, {
         cnpj: function(b, a) {
            return me.verificaCNPJ(b);
         },
         cnpjText: "CNPJ não é válido!"
      });

      Ext.apply(me, { vtype: 'cnpj' });

      me.callParent();
   },
   initEvents: function() {
      var me = this;
      var el = me.inputEl;

      el.on("keydown", me.stopEventFunction, me);
      el.on("keyup", me.formatCNPJ, me);
      el.on("keypress", me.stopEventFunction, me);
      el.on("focus", me.startCNPJ, me);
      el.on("blur", me.clearCNPJ, me);

      me.callParent();
   },
   KEY_RANGES: {
      numeric: [48, 57],
      padnum: [96, 105]
   },
   isInRange: function(a, b) {
      return a >= b[0] && a <= b[1];
   },
   stopEventFunction: function(a) {
      var me = this;

      var b = a.getKey();
      if (me.isInRange(b, me.KEY_RANGES.padnum)) {
         b -= 48;
      }
      if (((b >= 41 && b <= 122) || b == 32 || b == 8 || b > 186) && (!a.altKey && !a.ctrlKey)) {
         a.stopEvent();
      }
   },
   startCNPJ: function() {
      var me = this;
      var a = me.inputEl.dom;

      if (a.value == "") {
         a.value = "";
         if (me.soNumero) {
            a.value = "000000000000000";
         } else {
            a.value = "000.000.000/0000-00";
         }
      }
   },
   clearCNPJ: function() {
      var me = this;
      var a = me.inputEl.dom;
      if (a.value == "000.000.000/0000-00" || a.value == "000000000000000"){
         a.value = "";
         me.validate();
      }
   },
   formatCNPJ: function(k) {
      var me = this;
      var e = me.inputEl.dom;

      var j = k.getKey();
      if (me.isInRange(j, me.KEY_RANGES.padnum)) {
         j -= 48;
      }
      var d = (me.isInRange(j, me.KEY_RANGES.numeric) ? String.fromCharCode(j) : "");
      var h = (e.value.replace(/\D/g, "").substr(1) + d).replace(/\D/g, "");

      var a = h.length;
      if (d == "" && a > 0 && j == 8) {
         a--;
         h = h.substr(0, a);
         k.stopEvent();
      }
      if (e.maxLength + 1 && a >= e.maxLength) {
         return false;
      }
      if (a < 15) {
         var b = "";
         for (var c = 0; c < 15 - a; c++) {
            b = b + "0";
         }
         h = b + h;
         a = 15;
      }
      if (me.soNumero) {
         e.value = h;
      } else {
         var l = "";
         l = h.substr(0, 3) + "." + h.substr(3, 3) + "." + h.substr(6, 3) + "/" + h.substr(9, 4) + "-" + h.substr(13);
         e.value = l;
      }
   },
   verificaCNPJ: function(a) {
      var me = this;
      if (a == "") return true;

      a = a.replace(/\D/g, "");
      a = a.replace(/^0+/, "");
      if (parseInt(a, 10) == 0) {
         return false;
      } else {
         g = a.length - 2;
         if (me.testaCNPJ(a, g) == 1) {
            g = a.length - 1;
            if (me.testaCNPJ(a, g) == 1) {
               return true;
            } else {
               return false;
            }
         } else {
            return false;
         }
      }
   },
   testaCNPJ: function(a, d) {
      var b = 0;
      var e = 2;
      var c;
      for (f = d; f > 0; f--) {
         b += parseInt(a.charAt(f - 1),10) * e;
         if (e > 8) {
            e = 2;
         } else {
            e++;
         }
      }
      b %= 11;
      if (b == 0 || b == 1) {
         b = 0;
      } else {
         b = 11 - b;
      }
      if (b != parseInt(a.charAt(d),10)) {
         return (0);
      } else {
         return (1);
      }
   }
});

Arquivo da Aplicação – Form:

Ext.Loader.setConfig({enabled: true});

Ext.require([
	'Ux.CpfField',
	'Ux.CnpjField'
]);

Ext.onReady(function() {
	
	Ext.create('Ext.form.Panel', {
		renderTo: Ext.getBody(),
		title: 'Exemplo Campos CPF e CNPJ',
		width: 250,
		bodyPadding: 5,
		fieldDefaults: {
			labelAlign: 'left',
			labelWidth: 50,
			anchor: '100%',
			msgTarget: 'under'
		},
		defaultType: 'textfield',
		items: [{
			fieldLabel: 'CPF', 
			name: 'campoCPF', 
			xtype: 'cpffield'
		},{
			fieldLabel: 'CNPJ', 
			name: 'campoCNPJ', 
			xtype: 'cnpjfield'
		}]
	});
	
});

HTML:

<html>
<head>
    <link rel="stylesheet" type="text/css" href="ext4/resources/css/ext-all.css" />
    <style type="text/css">
	    body {
			padding:20px;
		}
    </style>

    <script type="text/javascript" src="ext4/ext-all.js"></script>
    <script type="text/javascript" src="app.js"></script>
</head>
<body>
</body>
</html>

Estrutura de diretórios do exemplo:

extjs4 cpf cnpj loiane 01 ExtJS 4 Form: Exemplo Campos CPF e CNPJ

Obs.: usei um projeto js no Eclipse para desenvolver esse exemplo.

Download do código fonte:

Github:https://github.com/loiane/extjs4-cpf-cnpj-fields

Google Code:https://code.google.com/p/extjs4-cpf-cnpj-fields/downloads/list

Disclaimer: não sou a autora desses plugins de CPF e CNPJ; apenas postei os exemplos de como usá-los aqui no blog. Quaisquer dúvidas em relação ao código do plugin, compatibilidade com outras versões do Ext JS, etc, favor perguntar no fórum do ExtJS BR nos seguintes tópicos:

CPF: http://www.extjs.com.br/forum/index.php?topic=5125.0

CNPJ: http://www.extjs.com.br/forum/index.php?topic=5124.0

Bons códigos!

Filed in: Ext JS 4 | Tags: , , , ,

Comments (8)

  1. Guilherme

    Boa tarde. Gostei, meus parabéns!

  2. Olá Loiane.
    Estou começando um projeto de extjs4 e estou fazendo com o designer.
    Para alterar o xtype do field usei o
    Ext.apply(me.txtPersonDocument, {
    xtype: ‘cpffield’
    });
    Object { initialConfig={…}, xtype=”cpffield”, itemId=”txtPersonDocument”, more…}

    mais quando digito no field, ele não faz a máscara de cpf e muito menos a validação.

    Poderia me ajudar?

    Obrigado

    • Olá João Paulo,
      Infelizmente não trabalho com Ext Designer.
      Qualquer plugin deve ser instanciado antes de ser usado.
      Obrigada!

  3. Só funcionou quando editei o xtype no Ui
    da Janela. O plugin deve ser instanciado
    antes de criar a janela, pelo que entendi.
    Sou meio iniciante, mais teria alguma
    forma de mudar o xtype ou qualquer outro
    atributo da janela antes de criar a mesma?

    Obrigado…

    ( se eu achar uma solução antes eu posto aqui
    para ajudar os próximos :D )

  4. A maneira que encontrei foi, tirar o txt do designer e criar o mesmo dependendo
    do radio que ele marcar.
    Marcou CPF, da um .add no container e no create ja seto o xtype: cpffield.
    Se encontrarem uma maneira melhor… estarei interessando :D

    Abraço!

  5. Modifiquei o código para melhorar a forma como a mascara fica, o código original a mascara vinha de traz para frente, deixava a pessoa digitar infinitamente, ficando bem esquisito.
    O campo não inicializa com 000. Modifiquei o parametro soNumeros para onlyNumber como sugerido.
    E o código de mascara é reutiliza-vel podendo a pessoa definir suas proprias máscaras em qualquer campo textfield.

    Em resumo eu aproveitei a validação de cpf e cnpj e melhorei a mascara.

    O arquivo fonte está em https://bitbucket.org/giovanni/extjs
    Esta sob controle de versão usando mercurial. Esse projeto irei colocar tudo que for reutilizável para qualquer sistema em EXTJS, sob uma licença opensource apache 2.0 significando que pode ser usando em projetos comerciais também.

    Recomendo clonar o repositório em uma pasta do seu projeto assim vc pode atualizá-lo facilmente.

    Quem quiser contribuir entra em contato para trocarmos idéias e posso liberar acesso de escrita no repositório.

    Se acharem algum bug podem reportar também por lá. Há também uma wiki com a utilização básica mas não tive tempo de criar uma documentação mais completa.

    Bons códigos ;)