Prática recomendada: acesse elementos do formulário pelo atributo HTML id ou name?


136

Como qualquer desenvolvedor experiente de JavaScript sabe, existem muitas maneiras (demais) de fazer a mesma coisa. Por exemplo, digamos que você tenha um campo de texto da seguinte maneira:

<form name="myForm">  
    <input type="text" name="foo" id="foo" />

Há muitas maneiras de acessar isso em JavaScript:

[1]  document.forms[0].elements[0];
[2]  document.myForm.foo;
[3]  document.getElementById('foo');
[4]  document.getElementById('myForm').foo;
     ... and so on ...

Os métodos [1] e [3] estão bem documentados na documentação do Mozilla Gecko, mas nenhum deles é o ideal. [1] é geral demais para ser útil e [3] requer um ID e um nome (supondo que você esteja postando os dados em um idioma no servidor). Idealmente, seria melhor ter apenas um atributo id ou um nome (ter ambos é um pouco redundante, especialmente se o id não for necessário para qualquer css e aumenta a probabilidade de erros de digitação, etc.).

[2] parece ser o mais intuitivo e amplamente utilizado, mas não o vi mencionado na documentação do Gecko e estou preocupado com a compatibilidade avançada e a compatibilidade entre navegadores (e, é claro, quero ser conforme os padrões possíveis).

Então, qual é a melhor prática aqui? Alguém pode apontar para algo na documentação do DOM ou na especificação do W3C que possa resolver isso?

Observe que estou especificamente interessado em uma solução que não é de biblioteca (jQuery / Prototype).


Eu acho que o que ferve para baixo é que eu estou olhando para a maioria dos padrões de maneira compatível com o acesso de um elemento de formulário usando o atributo de nome ...
Seth

4
"ter os dois é um tanto redundante, especialmente se o ID não é necessário para qualquer CSS e aumenta a probabilidade de erros de digitação" - o ID é necessário para o uso eficaz de rótulos. Não apenas CSS.

Às vezes, existem vários formulários em uma página da Web e os atributos de identificação podem colidir.
Calmarius

Respostas:


96

Dê ao seu formulário apenas um ID e sua entrada apenas um nome :

<form id="myform">
  <input type="text" name="foo">

Em seguida, a maneira mais compatível com os padrões e menos problemática de acessar seu elemento de entrada é através de:

document.getElementById("myform").elements["foo"]

usar em .elements["foo"]vez de just .fooé preferível, pois o último pode retornar uma propriedade do formulário chamado "foo" em vez de um elemento HTML!


1
@Karl ... O que você está tentando alcançar? Além do fato de que a inclusão de JS no HTML é bastante deselegante (e muitas vezes ineficiente, pois cria uma função de invólucro em torno do código), o fato de você sempre retornar falso significa que seu formulário nunca será enviado. Portanto, a menos que o formulário não deva ser enviado (talvez seja usado inteiramente pelo código JS), ou a menos que myFunc (isto) o envie via AJAX (e você não se importa em fazer um envio regular como substituto no caso de AJAX falha de alguma forma), ... então você cometeu um erro.
Doin

1
Normalmente, para apresentar apenas dados forma válida, você faria: myform.onsubmit = validateForm;(onde myform é uma variável que faz referência ao elemento do formulário, e validateForm é o nome da sua função de validação ... mas você pode nomeá-lo myFunc se você realmente , realmente querem ) O ponto importante é que ele validateForm()retorne false sempre que o formulário não for válido, além de indicar o (s) campo (s) do problema para o usuário. Ele deve retornar true quando os dados do formulário forem validados corretamente, o que permitirá que a ação de envio prossiga.
Doin

2
Há outro motivo para evitar IDs nos campos do formulário: caso você queira várias instâncias do mesmo formulário (na mesma página).
precisa saber é o seguinte

1
@ João que também funciona, desde que "foo" seja válido como um nome de propriedade javascript. (Pode não ser - HTML5 quase não impõe restrições ao valor do nameatributo, por exemplo, você pode ter <select name="a+b">ou <input type="text" name="...2">, que não pode ser referenciado usando a notação javascript .propertyName). A notação explícita [] também permite nomes criados a partir de expressões, por exemplo myCheckBox = document.getElementById("myform").elements["CHK"+i]. Além disso, estilisticamente, acho [] melhor - deixa claro que essas não são apenas propriedades de um objeto javascript. YMMV.
Doin

1
Em relação ao uso de linting, lembre-se de que o linting é apenas um guia de estilo e um "erro" de linting não significa que seu javascript é inválido ou incorreto. Nesse caso em particular, no entanto, o que a regra do linting está dizendo é "prefira a notação de ponto ao fazer referência às propriedades do objeto javascript". É uma boa ideia, e eu recomendo isso em geral. MAS enquanto o linter não percebe isso, elementsnão é um objeto JS normal e elements.fooou elements["foo"]está realmente sendo convertido em elements.namedItem ("foo"). ou seja, você está chamando uma função definida pelo DOM , não referenciando uma propriedade JS!
Doin

34

[1] document.forms [0] .elements [0];

" No-omg-never! " Me vem à mente quando vejo esse método de acesso ao elemento. O problema é que assume que o DOM é uma estrutura de dados normal (por exemplo, uma matriz) em que a ordem dos elementos é estática, consistente ou confiável de qualquer maneira. Sabemos que 99,9999% do tempo, que esse não é o caso. Reordenar ou inputelementos no formulário, adicionar outro formà página antes do formulário em questão ou mover o formulário em questão são todos os casos em que esse código é quebrado. História curta: isso é muito frágil. Assim que você adicionar ou mover algo, ele quebrará.

[2] document.myForm.foo;

Estou com Sergey ILinsky sobre isso:

  • Acesse elementos arbitrários consultando seu idatributo:document.getElementById("myform");
  • Acesse elementos de formulário nomeados por nome, em relação ao elemento de formulário pai: document.getElementById("myform").foo;

Meu principal problema com este método é que o nameatributo é inútil quando aplicado a um formulário. O nome não é passado para o servidor como parte do POST / GET e não funciona para indicadores de estilo de hash.

[3] document.getElementById ('foo');

Na minha opinião, este é o método mais preferível. O acesso direto é o método mais conciso e claro.

[4] document.getElementById ('myForm'). Foo;

Na minha opinião, isso é aceitável, mas mais detalhado do que o necessário. O método nº 3 é preferível.


Por acaso, assisti a um vídeo de Douglas Crockford e ele comentou sobre esse assunto. O ponto de interesse é às -12: 00. Para resumir:

  • As coleções de documentos (document.anchor, document.form, etc) são obsoletas e irrelevantes (método 1).
  • O nameatributo é usado para nomear coisas, não para acessá-las. É para nomear coisas como janelas, campos de entrada e tags de âncora.
  • "A identificação é a coisa que você deve usar para identificar um elemento de forma exclusiva para ter acesso a ele. Eles (nome e ID) costumavam ser intercambiáveis, mas não são mais".

Então aí está. Semanticamente, isso faz mais sentido.


2
Então isso é apenas um truque? document.getElementById ("myform"). foo; Depois de estudar bastante o DOM, não sei ao certo por que isso funciona. Meu palpite é o objeto de formulário também é um array de seu filho elementos indexados no atributo nome html ...
Seth

1
Você também menciona "o nome não é passado para o servidor como parte do POST / GET e não funciona para indicadores de estilo de hash". Não é exatamente isso que é passado para o servidor? Quando você está trabalhando com PHP, é o atributo name que é seu índice no global $ _POST.
seth

2
@ Justin, é o atributo name que é passado para o servidor.
Anurag

2
@seth As especificações DOM mais antigas parecem muito vagas sobre o porquê document.aForm.foofunciona, mas a especificação HTML5 parece definir claramente a interface de uma HTMLFormElementque possui caller getter any namedItem(in DOMString name);. Mais em whatwg.org/specs/web-apps/current-work/multipage/…
Anurag

1
@ ambos: "... o atributo name é inútil quando aplicado a um formulário ..." Eu não estou falando sobre o atributo name de um inputou select, estou falando sobre o atributo name de a form. O atributo name de a form não é passado para o servidor.
Justin Johnson

14

Para acessar os elementos nomeados colocados em um formulário, é uma boa prática usar o formpróprio objeto.

Para acessar um elemento arbitrário na árvore do DOM que pode ser encontrado ocasionalmente em um formulário, use getElementByIde os do elemento id.


8
O que você quer dizer com "usar o próprio objeto de formulário"? Depois de ter o objeto de formulário, qual método você usa para acessar um elemento específico?
seth

2
Quero dizer, eu recomendaria o uso de N5 (document.getElementById ('myForm'). Elements.foo) para acessar itens nomeados e N6 (document.getElementById ('myForm'). Elementos) para acessar a coleção iterável de elementos
Sergey Ilinsky

Estou definindo o estilo do meu código ... e, como preferência, continuo com os IDs .... desse modo, o acesso ao elemento é consistente em toda a página. + os outros motivos mencionados.

1
Por que é uma boa prática acessar o formulário usando getElementID? por que document.myForm não funcionou? (Eu tenho uma situação onde não o seu trabalho e eu estou querendo saber o porquê)
Spundun

Ei Spundun, você provavelmente já resolveu seu problema meses atrás (ou talvez tenha levantado as mãos para cima :)), mas, caso esteja se perguntando, provavelmente foi porque você não forneceu ao elemento HTML do formulário um atributo "name".
Sheldon R.

8

Eu prefiro muito o quinto método. Isso é
[5] Use o identificador JavaScript especial this para passar o formulário ou o objeto de campo para a função do manipulador de eventos.

Especificamente, para formulários:

<form id="form1" name="form1" onsubmit="return validateForm(this)">

e

// The form validation function takes the form object as the input parameter
function validateForm(thisForm) {
  if (thisform.fullname.value !=...

Usando essa técnica, a função nunca precisa saber
- a ordem na qual os formulários são definidos na página
- o ID do formulário nem
- o nome do formulário

Da mesma forma, para os campos:

<input type="text" name="maxWeight">
...
<input type="text" name="item1Weight" onchange="return checkWeight(this)">
<input type="text" name="item2Weight" onchange="return checkWeight(this)">

e

function checkWeight(theField) {
  if (theField.value > theField.form.maxWeight.value) {
    alert ("The weight value " + theField.value + " is larger than the limit");
    return false;
  }
return true;
}

Nesse caso, a função nunca precisa saber o nome ou o ID de um campo de peso específico, embora precise saber o nome do campo de limite de peso.


Não sei qual é a causa subjacente, mas essa abordagem retornou cadeias vazias em algumas, mas não em todas as circunstâncias.
Jacob Lee

7

Não está realmente respondendo à sua pergunta, mas apenas nesta parte:

[3] requer um id e um nome ... tendo ambos é um tanto redundante

Você provavelmente precisará ter um idatributo em cada campo do formulário de qualquer maneira, para poder associar seu <label>elemento a ele, assim:

<label for="foo">Foo:</label>
<input type="text" name="foo" id="foo" />

Isso é necessário para a acessibilidade (ou seja, se você não associa rótulos e controles de formulário, por que você odeia tanto os cegos?).

É um pouco redundante, embora menos quando você tem caixas de seleção / botões de opção, onde vários deles podem compartilhar a name. Por fim, ide namesão para propósitos diferentes, mesmo que ambos sejam configurados com o mesmo valor.


5
Se você inserir uma entrada em seu rótulo, não precisará de um ID ou de um atributo. <label> Foo: <input type = "text" name = "foo" </label>
kennebec

3
É verdade, embora isso limite o que você pode conseguir em termos de aparência.
Paul D. Waite

2
@ kennebec - você sempre deve usar um ID se quiser que o rótulo seja associado a um elemento. Versões mais antigas do IE (<8?) Não elementos associados dentro de um rótulo com o rótulo se não houvesse correspondência por e id atributos.
precisa saber é

Além do que a @kennebec escreveu, o uso de IDs cria JS globais e deve ser evitado.
Mikemaccana

1
@mikemaccana: Eu já vi isso causar problemas antes. Acho que, se seus IDs são razoavelmente descritivos e seu JavaScript é sensivelmente espaçado por nome, é improvável que isso cause problemas.
Paul D. Waite

6

Isso é um pouco antigo, mas quero acrescentar algo que acho relevante.
(Pretendia comentar um ou dois tópicos acima, mas parece que preciso da reputação 50 e tenho apenas 21 no momento em que escrevo isso. :))
Quero apenas dizer que há momentos em que é muito melhor acessar o elementos de um formulário por nome e não por id. Eu não estou falando sobre o próprio formulário. O formulário, OK, você pode atribuir um ID e depois acessá-lo. Mas se você tiver um botão de opção em um formulário, é muito mais fácil usá-lo como um único objeto (obtendo e definindo seu valor) e você só poderá fazer isso pelo nome, tanto quanto eu saiba.

Exemplo:

<form id="mainForm" name="mainForm">
    <input type="radio" name="R1" value="V1">choice 1<br/>
    <input type="radio" name="R1" value="V2">choice 2<br/>
    <input type="radio" name="R1" value="V3">choice 3
</form>

Você pode obter / definir o valor verificado do botão de opção R1 como um todo usando
document.mainForm.R1.value
ou
document.getElementById ("mainForm"). R1.value
Portanto, se você quiser ter um estilo unitário, poderá deseja sempre usar esse método, independentemente do tipo de elemento do formulário. Eu, estou perfeitamente confortável em acessar botões de opção por nome e caixas de texto por identificação.


O que funciona é document.forms.mainForm.R1.valueque é realmente uma boa maneira de evitar o uso do feio e tedioso do tipodocument.getElementById()
Kai Carver

2

Sendo antiquado, sempre usei a sintaxe 'document.myform.myvar', mas recentemente descobri que ela falhou no Chrome (OK no Firefox e IE). Era uma página Ajax (isto é, carregada na propriedade innerHTML de uma div). Talvez o Chrome não tenha reconhecido o formulário como um elemento do documento principal. Eu usei getElementById (sem referenciar o formulário) e funcionou OK.


você pode simplesmente inserir .forms, então document.forms.myform.myvar
Kai Carver

1

Apenas para adicionar a tudo o que foi dito, você pode acessar os inputs com nameou idusando preferencialmente a elementspropriedade do formulário Objeto, porque sem ele você pode obter uma propriedade do formulário chamado "foo" em vez de um elemento HTML. E de acordo com @Paul D. Waite, é perfeitamente aceitável ter nome e identificação.

var myForm = document.getElementById("myform")
console.log(myForm.foo.value) // hey
console.log(myForm.foo2.value) // hey
//preferable
console.log(myForm.elements.foo.value) // hey
console.log(myForm.elements.foo2.value) // hey
<form id="myform">
  <input type="text" name="foo" id="foo2" value="hey">
</form>

De acordo com o MDN na página HTMLFormElement.elements

Os elementos da propriedade HTMLFormElement retornam um HTMLFormControlsCollection listando todos os controles de formulário contidos no elemento. Independentemente, você pode obter apenas o número de controles de formulário usando a propriedade length.

Você pode acessar um controle de formulário específico na coleção retornada usando um índice ou o nome ou o ID do elemento .


1

namecampo funciona bem. Ele fornece uma referência ao elements.

parent.children- Irá listar todos os elementos com um campo de nome do pai. parent.elements- Listará apenas form elementscomoinput-text, text-area, etc

var form = document.getElementById('form-1');
console.log(form.children.firstname)
console.log(form.elements.firstname)
console.log(form.elements.progressBar); // undefined
console.log(form.children.progressBar);
console.log(form.elements.submit); // undefined
<form id="form-1">
  <input type="text" name="firstname" />
  <input type="file" name="file" />
  <progress name="progressBar" value="20" min="0" max="100" />
  <textarea name="address"></textarea>
  <input type="submit" name="submit" />
</form>

Nota: Para .elementstrabalhar, as parentnecessidades precisam ser a <form> tag. Visto .childrenque funcionará em qualquer um HTML-element- como <div>, <span>, etc.

Boa sorte...


0

O formulário 2 está ok e o formulário 3 também é recomendado.
A redundância entre nome e id é causada pela necessidade de manter a compatibilidade. No html 5, alguns elementos (como img, form, iframe e outros) perdem o atributo "name" e é recomendável usar apenas o id para referenciá-los a partir de agora em :)


Parece que os elementos de entrada nunca perderão o atributo name devido à maneira como são usados ​​pelos idiomas do servidor. Portanto, a questão permanece: qual é o método compatível com os padrões se você tiver apenas o atributo name definido?
Seth

Em um desenvolvimento compatível com os padrões, você não teria apenas o nome, para iniciantes. Se você realmente NÃO PODE ter ID, sugiro a função document.getElementByName ().
Wintermute

0

Para complementar as outras respostas, document.myForm.foo é o chamado DOM nível 0, que é o caminho implementado pelo Netscape e, portanto, não é realmente um padrão aberto, embora seja suportado pela maioria dos navegadores.


4
O acesso a formulários e controles de formulários por nome, ID e índice faz parte do padrão HTML do DOM 2 para coleções de HTML .
RobG

0

Confira esta página: https://developer.mozilla.org/En/DOM/Document.getElementsByName

document.getElementsByName('foo')[0]; // returns you element.

Ele deve ser 'elementos' e deve retornar uma matriz, pois mais de um elemento pode ter o mesmo nome.


@robert, agora estou pensando que essa pode ser uma boa solução, embora isso tenha saído dos documentos me deixando nervoso: "Esse método pode ser questionável devido às alterações acima entre os tipos de documento e o comportamento não padrão atual para isso". método em XHTML. "
seth

Olá. Qual documentação sugeriu isso? Acho que se você estiver usando xhtml em todos os ambientes DOM em que está trabalhando, deve estar bem. Além disso, quais navegadores não suportam isso? Aqui estão os documentos para o IE: msdn.microsoft.com/en-us/library/ms536438(VS.85).aspx Além do Mozilla acima, quem mais pode não suportá-lo?
22610 robert

0

Minha resposta será diferente na pergunta exata. Se eu quiser acessar um determinado elemento especificamente, usarei document.getElementById (). Um exemplo é computar o nome completo de uma pessoa, porque é baseado em vários campos, mas é uma fórmula repetível.

Se eu quiser acessar o elemento como parte de uma estrutura funcional (um formulário), usarei:

var frm = document.getElementById('frm_name');
for(var i = 0; i < frm.elements.length;i++){
   ..frm.elements[i]..

É assim que também funciona da perspectiva dos negócios. As alterações no loop acompanham as alterações funcionais no aplicativo e, portanto, são significativas. Eu o aplico principalmente para validação amigável e para evitar chamadas de rede para verificação de dados incorretos. Repito o lado do servidor de validação (e acrescento um pouco mais a ele), mas se eu puder ajudar o lado do cliente do usuário, isso será benéfico para todos.

Para agregação de dados (como a construção de um gráfico de pizza com base nos dados do formulário), uso documentos de configuração e objetos Javascript personalizados. Então, o significado exato do campo é importante em relação ao seu contexto e eu uso document.getElementById ().


0

Porque o caso [2] document.myForm.fooé um dialeto do Internet Exploere. Então, em vez disso, eu prefiro document.forms.myForm.elements.fooou document.forms["myForm"].elements["foo"].


Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.