julho 2009
D S T Q Q S S
« mai   fev »
 1234
567891011
12131415161718
19202122232425
262728293031  

Reset de formulário turbinado

Quem nunca fez um formulário com um select, um radio ou um checkbox que mostra ou esconde outro trecho do formulário? Isto é uma prática bem comum, mas que o método reset () do formulário não tem como tratar.

Pesquisando um pouco, encontrei as propriedades defaultValue, defaultSelected e defaultChecked nos objetos de formulário do DOM. Com isso, podemos simular o método reset () do formulário. A propriedade defaultValue é válida para elementos do tipo text, password, textarea e file, a propriedade defaultSelected é válida para elementos option, e a propriedade defaultChecked é válida para elementos checkbox e radio.

Com isso, podemos criar facilmente uma função para resetar os valores de um formulário para o seu padrão:

function formReset ( formID)
{
  // Fazemos um laço por todos os elementos do formulário:
  for ( var x = 0; x < formID.elements.length; x++)
  {
    // Verificamos o tipo de elemento:
    switch ( formID.elements[x].type)
    {
      case 'text':
      case 'textarea':
      case 'password':
      case 'file':
        // Campos tipo text, textarea, password e file utilizam defaultValue:
        formID.elements[x].value = formID.elements[x].defaultValue;
        break;
      case 'select':
      case 'select-one':
        // Campos tipo select são tratados de forma especial. Temos que criar outro laço em seus elementos option para utilizar defaultSelected:
        for ( var y = 0; y < formID.elements[x].options.length; y++)
        {
          formID.elements[x].options[y].selected = formID.elements[x].options[y].defaultSelected;
        }
        break;
      case 'radio':
      case 'checkbox':
        // Campos tipo radio e checkbox utilizam defaultChecked:
        formID.elements[x].checked = formID.elements[x].defaultChecked;
        break;
    }
  }
}

Você deve estar pensando: Tá, e daí? Isso o método reset () faz! Bom, é aqui que podemos começar a brincar com o reset do formulário. Para começar, podemos dentro do laço fazer com que ele verifique se o elemento possui algum evento onchange, e caso exista, execute o mesmo após alterar o valor para o padrão. Ou seja, irá simular como se o usuário estivesse alterando o valor do formulário.

Podemos fazer isso assim:

if ( typeof ( formID.elements[x].onchange) == 'function')
{
  formID.elements[x].onchange ();
}

Com isso podemos incluir todo tratamento necessário do formulário no evento onchange do elemento, para que quando resetarmos o formulário através da função formReset () ele execute estas funções e retorne o formato original do formulário.

Mas não podemos executar o evento onchange de cada elemento, pois se o valor não foi alterado, não devemos executar. Isso serve principalmente para eventos checkbox. Por isso, temos que reescrever a função, ficando assim:

function formReset ( formID)
{
  // Fazemos um laço por todos os elementos do formulário:
  var changed = false;
  for ( var x = 0; x < formID.elements.length; x++)
  {
    // Verificamos o tipo de elemento:
    switch ( formID.elements[x].type)
    {
      case 'text':
      case 'textarea':
      case 'password':
      case 'file':
        // Campos tipo text, textarea, password e file utilizam defaultValue:
        if ( formID.elements[x].value != formID.elements[x].defaultValue)
        {
          formID.elements[x].value = formID.elements[x].defaultValue;
        }
        break;
      case 'select':
      case 'select-one':
        // Campos tipo select são tratados de forma especial. Temos que criar outro laço em seus elementos option para utilizar defaultSelected:
        for ( var y = 0; y < formID.elements[x].options.length; y++)
        {
          if ( formID.elements[x].options[y].selected != formID.elements[x].options[y].defaultSelected)
          {
            formID.elements[x].options[y].selected = formID.elements[x].options[y].defaultSelected;
          }
        }
        break;
      case 'radio':
      case 'checkbox':
        // Campos tipo radio e checkbox utilizam defaultChecked:
        if ( formID.elements[x].checked != formID.elements[x].defaultChecked)
        {
          formID.elements[x].checked = formID.elements[x].defaultChecked;
        }
        break;
    }
    // Se o elemento teve o valor alterado, executa o método onchange () (se definido):
    if ( changed == true && typeof ( formID.elements[x].onchange) == 'function')
    {
      formID.elements[x].onchange ();
      changed = false;
    }
  }
}

Podemos ainda incrementar um pouco mais, fazendo com que o foco seja apontado para o primeiro campo que seja do tipo text, select, password, radio ou checkbox:

function formReset ( formID)
{
  // Fazemos um laço por todos os elementos do formulário:
  var focusElement;
  var changed = false;
  for ( var x = 0; x < formID.elements.length; x++)
  {
    // Verificamos se ainda não existe elemento para foco setado, e o tipo de elemento. Se combinado, seta a variável:
    if ( ! focusElement && ( formID.elements[x].type == 'text' || formID.elements[x].type == 'select' || formID.elements[x].type == 'password' || formID.elements[x].type == 'checkbox' || formID.elements[x].type == 'radio'))
    {
      focusElement = formID.elements[x];
    }
    // Verificamos o tipo de elemento:
    switch ( formID.elements[x].type)
    {
      case 'text':
      case 'textarea':
      case 'password':
      case 'file':
        // Campos tipo text, textarea, password e file utilizam defaultValue:
        if ( formID.elements[x].value != formID.elements[x].defaultValue)
        {
          formID.elements[x].value = formID.elements[x].defaultValue;
        }
        break;
      case 'select':
      case 'select-one':
        // Campos tipo select são tratados de forma especial. Temos que criar outro laço em seus elementos option para utilizar defaultSelected:
        for ( var y = 0; y < formID.elements[x].options.length; y++)
        {
          if ( formID.elements[x].options[y].selected != formID.elements[x].options[y].defaultSelected)
          {
            formID.elements[x].options[y].selected = formID.elements[x].options[y].defaultSelected;
          }
        }
        break;
      case 'radio':
      case 'checkbox':
        // Campos tipo radio e checkbox utilizam defaultChecked:
        if ( formID.elements[x].checked != formID.elements[x].defaultChecked)
        {
          formID.elements[x].checked = formID.elements[x].defaultChecked;
        }
        break;
    }
    // Se o elemento teve o valor alterado, executa o método onchange () (se definido):
    if ( changed == true && typeof ( formID.elements[x].onchange) == 'function')
    {
      formID.elements[x].onchange ();
      changed = false;
    }
  }
  // Antes de encerrar, caso exista um campo escolhido para foco, executa o método focus () do mesmo:
  if ( focusElement)
  {
    focusElement.focus ();
  }
}

E para finalizar, vamos fazer uma última implementação. Que tal substituir o método reset () da classe HTMLFormElement do DOM para que todos os formulários do documento utilizem a função? Simples. Basta declarar a função assim (AVISO: apenas navegadores compatíveis como padrão W3C conseguem extender esta classe.):

// Altera o método reset () para a nossa própria classe:
HTMLFormElement.prototype.reset = function ()
{
  // Fazemos um laço por todos os elementos do formulário:
  var focusElement;
  var changed = false;
  for ( var x = 0; x < this.elements.length; x++)
  {
    // Verificamos se ainda não existe elemento para foco setado, e o tipo de elemento. Se combinado, seta a variável:
    if ( ! focusElement && ( this.elements[x].type == 'text' || this.elements[x].type == 'select' || this.elements[x].type == 'password' || this.elements[x].type == 'checkbox' || this.elements[x].type == 'radio'))
    {
      focusElement = this.elements[x];
    }
    // Verificamos o tipo de elemento:
    switch ( this.elements[x].type)
    {
      case 'text':
      case 'textarea':
      case 'password':
      case 'file':
        // Campos tipo text, textarea, password e file utilizam defaultValue:
        if ( this.elements[x].value != this.elements[x].defaultValue)
        {
          this.elements[x].value = this.elements[x].defaultValue;
          changed = true;
        }
        break;
      case 'select':
      case 'select-one':
        // Campos tipo select são tratados de forma especial. Temos que criar outro laço em seus elementos option para utilizar defaultSelected:
        for ( var y = 0; y < this.elements[x].options.length; y++)
        {
          if ( this.elements[x].options[y].selected != this.elements[x].options[y].defaultSelected)
          {
            this.elements[x].options[y].selected = this.elements[x].options[y].defaultSelected;
            changed = true;
          }
        }
        break;
      case 'radio':
      case 'checkbox':
        // Campos tipo radio e checkbox utilizam defaultChecked:
        if ( this.elements[x].checked != this.elements[x].defaultChecked)
        {
          this.elements[x].checked = this.elements[x].defaultChecked;
          changed = true;
        }
        break;
    }
    // Se o elemento teve o valor alterado, executa o método onchange () (se definido):
    if ( changed == true && typeof ( this.elements[x].onchange) == 'function')
    {
      this.elements[x].onchange ();
      changed = false;
    }
  }
  // Antes de encerrar, caso exista um campo escolhido para foco, executa o método focus () do mesmo:
  if ( focusElement)
  {
    focusElement.focus ();
  }
}

Isso resolve em partes, pois quando um reset é acionado como evento, a função não é executada. Para isso, devemos capturar o evento reset e alterar um pouco a função, para que ela referencie o formulário através da propriedade target do evento ou da palavra-chave this. O script final fica assim:

// Altera o método reset () para a nossa própria classe:
HTMLFormElement.prototype.reset = function ( event)
{
  // Verificamos como a função foi executada, setando a variável target:
  var target = event ? event.target : this;

  // Fazemos um laço por todos os elementos do formulário:
  var focusElement;
  var changed = false;
  for ( var x = 0; x < target.elements.length; x++)
  {
    // Verificamos se ainda não existe elemento para foco setado, e o tipo de elemento. Se combinado, seta a variável:
    if ( ! focusElement && ( target.elements[x].type == 'text' || target.elements[x].type == 'select' || target.elements[x].type == 'password' || target.elements[x].type == 'checkbox' || target.elements[x].type == 'radio'))
    {
      focusElement = target.elements[x];
    }
    // Verificamos o tipo de elemento:
    switch ( target.elements[x].type)
    {
      case 'text':
      case 'textarea':
      case 'password':
      case 'file':
        // Campos tipo text, textarea, password e file utilizam defaultValue:
        if ( target.elements[x].value != target.elements[x].defaultValue)
        {
          target.elements[x].value = target.elements[x].defaultValue;
          changed = true;
        }
        break;
      case 'select':
      case 'select-one':
        // Campos tipo select são tratados de forma especial. Temos que criar outro laço em seus elementos option para utilizar defaultSelected:
        for ( var y = 0; y < target.elements[x].options.length; y++)
        {
          if ( target.elements[x].options[y].selected != target.elements[x].options[y].defaultSelected)
          {
            target.elements[x].options[y].selected = target.elements[x].options[y].defaultSelected;
            changed = true;
          }
        }
        break;
      case 'radio':
      case 'checkbox':
        // Campos tipo radio e checkbox utilizam defaultChecked:
        if ( target.elements[x].checked != target.elements[x].defaultChecked)
        {
          target.elements[x].checked = target.elements[x].defaultChecked;
          changed = true;
        }
        break;
    }
    // Se o elemento teve o valor alterado, executa o método onchange () (se definido):
    if ( changed == true && typeof ( target.elements[x].onchange) == 'function')
    {
      target.elements[x].onchange ();
      changed = false;
    }
  }
  // Antes de encerrar, caso exista um campo escolhido para foco, executa o método focus () do mesmo:
  if ( focusElement)
  {
    focusElement.focus ();
  }
}

// Captura o evento onreset de todos os formulários do documento:
window.addEventListener ( 'reset', HTMLFormElement.prototype.reset, true);

Adicionei um formulário de testes aqui. Você também pode baixar o script aqui.

Envie uma resposta

 

 

 

Você pode utilizar estas tags HTML

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>