Título editável – exemplo de JavaScript/DOM

Vamos então aos posts com exemplos de códigos simples, mostrando o uso de uma ou mais das três camadas de desenvolvimento apresentadas nos dois posts anteriores.

Antes de começar, devo deixar claro que praticamente qualquer funcionalidade que você precise, seja em HTML, CSS ou JavaScript geralmente está a apenas uma “googlada” de distância. Se você tem um problema é muito provável que alguém já tenha tido o mesmo problema e a chance de que esse alguém já tenha resolvido e blogado sobre a solução também é muito grande.

O código feito aqui não se baseia em nenhum outro diretamente. Mas nada impede que eu use, inconscientemente (ou conscientemente, vai dizer) algo que eu já tenha visto por aí e tenha ficado registrado na caixola.

Vamos ao que interessa. Neste texto vamos fazer um título editável, ou seja, um título normal que, ao ser clicado se transforma em um campo de texto (INPUT) que ao perder o foco salva o novo valor e volta a ser um título novamente.

Começando pelo começo

A primeira coisa que precisamos é de uma página HTML com um título, no caso um H1, como pode ser visto no exemplo 1.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "www.w3.org/TR/html4/strict.dtd">
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <title>Título editável com JavaScript</title>
  <style type="text/css">
    h1 { 
      font:normal 2.4em/1.6 georgia, "times new roman", "bitstream vera serif", times, serif;
      color:#900;
    }
  </style>
  <script type="text/javascript">
  </script>
</head>
<body>
  <h1>Edite este título</h1>
</body>
</html>

Um Título simples, com um toquezinho de CSS só para definir a fonte e a cor, pra não ficar tosco demais. spacer

Note que o CSS e o JavaScript vão ser colocados dentro do próprio arquivo HTML, apenas para facilitar o estudo. No “mundo real” o ideal é colocá-los em arquivos separados.

Fazendo o título parecer editável

Precisamos agora dar alguma dica ao usuário de que, se clicado, o título pode ser editado.

Uma mudança na cor de fundo em conjunto com um texto explicativo no atributo TITLE do H1 me parecem ser suficientes. Além disso, vamos colocar um SPAN dentro do H1. Isso porque como o H1 é um elemento de bloco, ocupa por padrão 100% do espaço horizontal disponível. Para mudar isso poderíamos usar a propriedade CSS float ou definir uma largura específica para o H1. No caso do float, seria necessário definir a propriedade clear para o elemento logo abaixo do H1. Usar uma largura fixa não seria muito inteligente, pois o texto digitado pode ser maior que esse espaço. Portanto, fico com o SPAN.

Nesse ponto temos algo parecido com o exemplo 2.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "www.w3.org/TR/html4/strict.dtd">
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <title>Título editável com JavaScript</title>
  <style type="text/css">
    h1 { 
      font:normal 2.4em/1.6 georgia, "times new roman", "bitstream vera serif", times, serif;
      color:#900;
    }
    h1 span:hover{
      background:#f5f5f5;
    }
  </style>
  <script type="text/javascript">
  </script>
</head>
<body>
  <h1><span title="Clique para editar o texto">Edite este título</span></h1>
</body>
</html>

Você deve ter percebido que o exemplo 2 não funciona muito bem no Internet Explorer. Isso acontece porque o IE não tem suporte à pseudo-class :hover em elementos senão o A. Portanto, para obter esse efeito precisaremos de uma pitadinha de JavaScript.

Veja o exemplo 3. Perceba que coloquei o código todo dentro de uma função atribuída ao evento onload do objeto window, ou seja, o script será executado assim que o documento terminar de ser carregado pelo browser. Essa não é a melhor forma de fazer as coisas, mas por agora nos serve muito bem. Mais à frente veremos formas mais interessantes de “inicializar” nossos scripts.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "www.w3.org/TR/html4/strict.dtd">
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <title>Título editável com JavaScript</title>
  <style type="text/css">
    h1 { 
      font:normal 2.4em/1.6 georgia, "times new roman", "bitstream vera serif", times, serif;
      color:#900;
    }
  </style>
  <script type="text/javascript">
    window.onload = function(){
      var title = document.getElementsByTagName('h1')[0];
      var span = title.firstChild;
      span.onmouseover = function(){
        this.title = 'Clique para editar o texto';
        this.style.background = '#f5f5f5';
      }
      span.onmouseout = function(){
        this.title = '';
        this.style.background = '';
      }
    }
  </script>
</head>
<body>
  <h1><span>Edite este título</span></h1>
</body>
</html>

Pense comigo. O título só será editável caso o browser tenha suporte a JavaScript, portanto é melhor que tanto a cor de fundo ao passar o mouse quanto o TITLE só existam quando o suporte estiver presente.

Explicando o script: na linha var title = document.getElementsByTagName('h1')[0]; colocamos na variável title uma referência para o primeiro elemento definido pela tag H1 no documento.

Na linha seguinte, var span = title.firstChild; pegamos o primeiro filho (firstChild) do H1 — que, no caso, é o SPAN, e jogamos para a variável span.

Nas linhas seguintes definimos, no evento onmouseover do SPAN, seu título e cor de fundo e no onmouseout limpamos esses valores. Simples, não? Pois bem, avancemos.

Criando um INPUT para edição do texto

Agora precisamos que, ao clicar no título, este se transforme em um INPUT para permitir a edição do texto.

Para isso vamos usar o evento onclick do nosso SPAN, como pode ser visto no exemplo 4.


<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "www.w3.org/TR/html4/strict.dtd">
  <meta http-equiv="content-type" content="text/html; charset=utf-8">
  <title>Título editável com JavaScript</title>
  <style type="text/css">
    h1 { 
      font:normal 2.4em/1.6 georgia, "times new roman", "bitstream vera serif", times, serif;
      color:#900;
    }
  </style>
  <script type="text/javascript">
    window.onload = function(){
      function editTitle(){
        var title = document.getElementsByTagName('h1')[0];
        var span = title.firstChild;
        span.onmouseover = function(){
          this.title = 'Clique para editar o texto';
          this.style.background = '#f5f5f5';
        }
        span.onmouseout = function(){
          this.title = '';
          this.style.background = '';
        }
        span.onclick = function(){
          var textoAtual = this.firstChild.nodeValue;
          var input = '<input type="text" value="'+textoAtual+'">';
          this.innerHTML = input;
          var field = this.firstChild;
          this.onclick = null;
          this.onmouseover = null;
          field.focus();
          field.select();
          field.onblur = function(){
            this.parentNode.innerHTML = this.value;
            editTitle();
          }
        }
      }
      editTitle();
    }
  </script>
</head>
<body>
  <h1><span>Edite este título</span></h1>
</body>
</html>

Note que o código dessa vez foi colocado dentro de uma função, editTitle() que é chamada logo após a sua definição. Já explico porque isso foi necessário. Primeiro vamos entender como o esquema funciona.

var textoAtual = this.firstChild.nodeValue; pega o texto contido no SPAN e joga para a variável textoAtual. Perceba o uso de firstChild. Abra o DOM Inspector e vá até o SPAN. Veja que dentro desse SPAN há um elemento, que é um textNode, representado por #text. Esse textNode é o primeiro filho (firstChild) do nosso SPAN e o seu valor (nodeValue) é o texto em si, no caso “Edite este texto”.

Logo abaixo criamos uma string, que é um código HTML representando um INPUT, já com o VALUE definido com o valor de textoAtual. Feito isso, colocamos essa string no innerHTML do SPAN. innerHTML é o conteúdo HTML presente dentro do elemento em questão.

Nesse momento, o input passa a ser o firstChild do SPAN. Guardamos uma referência para ele na variável field.

Agora limpamos os eventos onclick e onmouseover do SPAN, usando this.onclick = null; e this.onmouseover = null; (retire estas duas linhas do código e teste para entender o porquê disso) e depois jogamos o foco para o INPUT e selecionamos o texto nele contido.

O próximo passo é atualizar o valor do nosso SPAN (que é o pai [parentNode] do INPUT) no evento onblur (perda de foco) do INPUT e chamar a própria função editTitle() para garantir que o código continuará funcionando. Experimente retirar a chamada para a função editTitle() de field.onblur e teste para entender melhor.

[update]

Atualizando o valor do título ao pressionar ENTER

Sugeri que os leitores fizessem, como “dever de casa”, com que o valor do título fosse atualizado ao pressionarmos a tecla ENTER.

O’Marin fez e postou nos comentários, mas o código dele não funciona no Internet Explorer. Os outros browsers (pelo menos os gecko-based e o Opera) capturam o evento que acontece ao pressionarmos uma tecla e o joga na variável usada como parâmetro da função atribuida ao evento onkeypress. Já o IE captura esse evento e atribui a um objeto, o window.event.

Precisamos apenas checar se esse objeto existe e, em caso positivo, usá-lo para pegar o código da tecla pressionada. Caso não exista, usamos a variável do parâmetro (que, no meu exemplo, vai se chamar e).

Outra coisa que O’Marin faz e que poderia ser feito de uma forma mais adequada é repetir o código que já está sendo usado no evento onblur dentro do evento onkeypress. Podemos reutilizar o código já existente chamando o método blur() do objeto em questão, já que, ao pressionar enter, é interessante tirar o foco do INPUT. Veja no exemplo 5.


field.onblur = function(){
  this.parentNode.innerHTML = this.value;
  editTitle();
}
field.onkeypress = function(e){
  var keynum;
  if(window.event) // IE
    keynum = window.event.keyCode;
  else if(e.keyCode) // Netscape/Firefox/Opera
    keynum = e.keyCode;
  if (keynum == 13) this.blur();
}


Esse exemplo foi testado e funciona no IE, Firefox e Opera. Concordam comigo ou têm alguma solução melhor?

[/update]

Conclusão

É claro que para esse código se transformar em alguma coisa realmente útil é necessário guardar o valor do texto editado em algum lugar onde este persista (um banco de dados, por exemplo), mas isso fica para um outro post.

E, como dever de casa (hehe), tente fazer com que o texto seja atualizado quando o usuário pressionar ENTER. Quem conseguir, poste a solução nos comentários. Caso ninguém consiga, colocarei o código aqui, em um update do post.

Espero ter sido claro e que isto seja de utilidade para vocês pelo menos para ajudar a entender um pouquinho mais a camada de comportamento. Comentários são muito bem vindos.

Leia também:

  • Como selecionar elementos HTML via JavaScript/DOM
  • Tudo sobre Image Replacement
  • Como criar elementos HTML via JavaScript/DOM
  • Hospedagem de sites Dreamhost: 50% de desconto
Postado por Bruno Torres em 30 Jun 2006 Categorias: Web
15 Comentários »
« Padrões web: Desenvolvimento em camadas – Camada de comportamento
Menu com imagens e rollover – Exemplo de HTML e CSS »

15 Comentários sobre “Título editável – exemplo de JavaScript/DOM”

  1. Robson Ricardo disse:
    junho 30th, 2006 at 8:49 am

    Realmente gostei do exemplo.
    Me parece ser de grande utilidade isso. spacer
    Abraço

  2. O'Marin disse:
    junho 30th, 2006 at 3:52 pm

    Legal. Todo post é um clip no clipmarks, tudo ótimo ^^

    Lição de casa resolvida. Nada que o google não possa resolver. Procurei o seguinte termo: “javascript get the key pressed” e olhei os dois primeiros links. E pronto:


    field.onblur = function(){
    this.parentNode.innerHTML = this.value;
    editTitle();
    }
    field.onkeypress = function(event) {
    if (event.keyCode == 13) {
    this.parentNode.innerHTML = this.value;
    editTitle();
    }
    }

  3. Estevão Lucas disse:
    junho 30th, 2006 at 10:27 pm

    E awe!!
    muito bom esse post! muito bom msm….parabens!
    sobre o devezinho, eh realmento o que o O’Marin postou….mas soh que naum ficou um codigo crossbrowser! testei testei no ie….e naum funcionou.!! fui atras….e verifiquei que o ie pegava os eventos com a global e! mas naum era isso!
    quando jah estava desistindo……
    troquei if
    if (event.keyCode == 13) {
    por
    if (window.event.keyCode == 13) {
    e pronto!!
    ai soh jogei uma variavel antes:
    evento = (!window.event) ? event : window.event;
    if (evento.keyCode == 13) {
    e pronto!!

  4. O'Marin disse:
    julho 1st, 2006 at 12:12 pm

    Nossa o IE só atrapalha mesmo.

    Nem pensei no this.blur() heheh é a falta de costume com javascript.

  5. Arthur Lucena disse:
    julho 12th, 2006 at 4:45 pm

    Cara, muito útil esse exemplo. Deu para ter um ótima idéia de como manipular os elementos de um documento html ao nosso bel prazer. Agora sim podemos afirmar que linguagem Javascript está sendo devidamente utilizada =D

    É legal começar a estudar AJAX apartir de exmplos puros de html, javascript e css como este, sem linguagem de programação como php ou asp, a pessoa tem uma idéia melhor de como as coisas funcionam e se adapta melhor a nova “realidade” =)

    Muito obrigado por compartilhar seus conhecimentos.

  6. Juliano Dantas disse:
    setembro 29th, 2006 at 5:49 pm

    Achei muito útil e interessante. Valeu!

  7. Camila Camargo disse:
    dezembro 14th, 2006 at 7:23 pm

    Mto legal essa matéria, mas como poderíamos fazer ser para colocar mais de um campo na mesma tela com essa função???

    Att,

  8. Rodrigo Fernandes disse:
    dezembro 19th, 2006 at 10:17 am

    Parabéns!!Ótimos exemplos!!!

  9. asdfgh disse:
    janeiro 11th, 2007 at 3:32 pm

    asd

  10. Rafael Miranda disse:
    abril 17th, 2007 at 10:57 am

    Gostei do exemplo mas como jogo este tipo de aplicação para executar dentro de uma arquivo ASP.NET com C#?

  11. drikun disse:
    agosto 26th, 2007 at 3:44 pm

    Obrigado pelos ensinamentos mestre! ^^
    Agora minha duvida é fazer isso em todos os H1..
    nesse caso deveria fazer um FOR ???

    Grato

  12. Como selecionar elementos HTML via JavaScript/DOM disse:
    outubro 11th, 2007 at 3:00 am

    [...] sobre seleção de elementos HTML em JavaScript, a maioria delas com dúvidas relacionadas ao artigo sobre títulos editáveis, que publiquei por aqui há algum tempo atrás. Por isso resolvi escrever este artigo sobre esse [...]

  13. Acaz disse:
    janeiro 30th, 2008 at 1:13 pm

    muito legal isso!

  14. private krankenversicherung test disse:
    setembro 24th, 2011 at 3:24 pm

    Gruess Gott, ich finde Sie machen einen sehr schoenen Blog. Deine Artikel sind sehr gelungen. Ab jetzt habt ihr 1 begeisterten Fan mehr.
    Danke schoen

  15. The Circle Blog disse:
    dezembro 14th, 2011 at 6:48 am

    Hello there, simply turned into aware of your blog thru Google, and found that it is really informative. I’m gonna watch out for brussels. I will appreciate if you continue this in future. A lot of other folks will be benefited from your writing. Cheers!

Leave a Reply

gipoco.com is neither affiliated with the authors of this page nor responsible for its contents. This is a safe-cache copy of the original web site.