Передовая практика. Доступ к элементам формы по идентификатору HTML или атрибуту имени?

136

Как знает любой опытный разработчик JavaScript, есть много (слишком много) способов сделать то же самое. Например, скажем, у вас есть текстовое поле следующим образом:

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

Есть много способов получить доступ к этому в JavaScript:

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

Методы [1] и [3] хорошо документированы в документации Mozilla Gecko, но ни один из них не идеален. [1] является слишком общим, чтобы быть полезным, а [3] требует и идентификатор, и имя (при условии, что вы будете публиковать данные на языке сервера). В идеале было бы лучше иметь только атрибут id или атрибут name (наличие обоих является несколько избыточным, особенно если идентификатор не нужен для какого-либо CSS, и увеличивает вероятность опечаток и т. Д.).

[2] кажется наиболее интуитивно понятным и широко используемым, но я не видел, чтобы на него ссылались в документации Gecko, и меня беспокоит как прямая совместимость, так и кросс-браузерная совместимость (и, конечно, я хочу быть насколько это возможно в соответствии со стандартами).

Так что же лучше здесь делать? Может кто-нибудь указать на что-то в документации DOM или спецификации W3C, что может решить эту проблему?

Примечание. Меня особенно интересует небиблиотечное решение (jQuery / Prototype).

Seth
источник
Я думаю, что все сводится к тому, что я ищу наиболее совместимый со стандартами способ доступа к элементу формы, используя атрибут name ...
seth
4
«наличие обоих несколько избыточно, особенно если идентификатор не нужен ни для какого CSS, и увеличивает вероятность опечаток» - идентификатор необходим для эффективного использования меток. Не только CSS.
Иногда на веб-странице есть несколько форм, и атрибуты id могут конфликтовать.
Кальмарий,

Ответы:

96

Дайте вашей форме только идентификатор , а ваши входные данные только имя :

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

Тогда самый совместимый со стандартами и наименее проблемный способ получить доступ к вашему элементу ввода - это:

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

предпочтительнее использовать .elements["foo"]вместо just, .fooпоскольку последний может возвращать свойство формы с именем «foo», а не элемент HTML!

Doin
источник
1
@ Карл ... Чего ты пытаешься достичь? Помимо того факта, что встраивание JS в ваш HTML является довольно неэффективным (и часто неэффективным, поскольку он создает функцию-обертку вокруг кода), тот факт, что вы всегда возвращаете false, означает, что ваша форма никогда не будет отправлена. Таким образом, если форма не предназначена для отправки (возможно, она полностью используется кодом JS), или если myFunc (this) не отправит ее через AJAX (и вам не нужно делать обычную отправку в качестве запасного варианта в случае AJAX как-то не получается), ... тогда вы ошиблись.
Doin
1
Обычно, для отправки только допустимых данных формы, вы должны сделать: myform.onsubmit = validateForm;(где myform - это переменная, ссылающаяся на элемент формы, а validateForm - это имя вашей функции проверки ... но вы можете назвать ее myFunc, если вы действительно , действительно хотите ). Важным моментом является то, что validateForm()следует возвращать false, если форма недействительна, а также указывать проблемные поля для пользователя. Он должен возвращать true, когда данные формы проверяются правильно, что позволит выполнить действие отправки.
Doin
2
Есть еще одна причина, по которой следует избегать идентификаторов в полях формы: если вам нужно несколько экземпляров одной формы (на одной странице).
кориандр
1
@ João, который тоже работает, при условии, что "foo" допустимо в качестве имени свойства javascript. (Может и не быть - HTML5 почти не накладывает ограничений на значение nameатрибута, например, вы можете иметь <select name="a+b">или <input type="text" name="...2">, на которые нельзя ссылаться, используя нотацию javascript .propertyName). Явная нотация [] также допускает имена, построенные из выражений, например myCheckBox = document.getElementById("myform").elements["CHK"+i]. Кроме того, стилистически я думаю, что [] лучше - это дает понять, что это не просто свойства объекта javascript. YMMV.
Doin
1
Что касается linting, имейте в виду, что linting - это только руководство по стилю, а linting «error» не означает, что ваш javascript неверен или неверен. В этом конкретном случае, однако, то, что говорит правило linting, это «предпочитать точечные обозначения при обращении к свойствам объекта javascript». Это хорошая идея, и я рекомендую это в целом. НО в то время как ЛИНТЕР не понимает этого, elementsне является нормальным объектом JS, и elements.fooили elements["foo"]фактически получать преобразуется в elements.namedItem ( «Foo»). то есть вы вызываете определенную DOM функцию , а не ссылаетесь на свойство JS!
Doin
34

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

« Нет, боже, никогда! » Приходит на ум, когда я вижу этот метод доступа к элементам. Проблема заключается в том, что предполагается, что DOM - это нормальная структура данных (например, массив), в которой порядок элементов в любом случае является статическим, непротиворечивым или надежным. Мы знаем, что 99,9999% времени, что это не так. Переупорядочивание или inputэлементы в форме, добавление другого formна страницу перед соответствующей формой или перемещение рассматриваемой формы - все это случаи, когда этот код нарушается. Короткая история: это очень хрупкий. Как только вы добавите или переместите что-то, оно сломается.

[2] document.myForm.foo;

Я с Сергеем Ильинским по этому поводу

  • Получите доступ к произвольным элементам, ссылаясь на их idатрибут:document.getElementById("myform");
  • Получите доступ к именованным элементам формы по имени относительно их родительского элемента формы: document.getElementById("myform").foo;

Моя главная проблема с этим методом заключается в том, что nameатрибут бесполезен при применении к форме. Имя не передается на сервер как часть POST / GET и не работает для закладок в стиле хэш.

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

На мой взгляд, это наиболее предпочтительный метод. Прямой доступ - самый краткий и понятный метод.

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

На мой взгляд, это приемлемо, но более многословно, чем необходимо. Метод № 3 предпочтительнее.


Просто так случилось, что я смотрел видео от Дугласа Крокфорда, и он взвесил эту тему. Точка интереса в -12: 00. Подвести итоги:

  • Коллекции документов (document.anchor, document.form и т. Д.) Устарели и неактуальны (метод 1).
  • nameАтрибут используется , чтобы назвать вещи, а не к ним доступ. Он предназначен для именования таких вещей, как окна, поля ввода и теги привязки.
  • «Идентификатор - это то, что вы должны использовать для уникальной идентификации элемента, чтобы вы могли получить к нему доступ. Они (имя и идентификатор) раньше были взаимозаменяемыми, но они больше не являются».

Так что у вас есть это. Семантически это имеет смысл.

Джастин Джонсон
источник
2
Так это просто взлом? . document.getElementById ( "MyForm") Foo; После небольшого изучения DOM мне неясно, почему это работает. Я предполагаю, что объект формы также является массивом его дочерних элементов, проиндексированных по атрибуту html name ...
seth
1
Также вы упоминаете, что «имя не передается на сервер как часть POST / GET и не работает для закладок в стиле хэш». Разве это не то, что передается на сервер? Когда вы работаете с PHP, это атрибут name, который является вашим индексом в глобальном $ _POST.
Сет
2
@Justin, это атрибут name, который передается на сервер.
Анураг
2
@seth Старые спецификации DOM кажутся весьма расплывчатыми относительно того, почему document.aForm.fooработает, но спецификация HTML5, похоже, четко определяет интерфейс, HTMLFormElementкоторый имеет caller getter any namedItem(in DOMString name);. Больше на whatwg.org/specs/web-apps/current-work/multipage/…
Anurag
1
@ оба, ребята: «... атрибут name бесполезен при применении к форме ...» Я не говорю об атрибуте name inputили select, я говорю об атрибуте name a form. Атрибут имени form не передается на сервер.
Джастин Джонсон
14

Для доступа к именованным элементам, размещенным в форме, рекомендуется использовать сам formобъект.

Чтобы получить доступ к произвольному элементу в дереве DOM, который иногда может быть найден в форме, используйте getElementByIdи элемент id.

Сергей Ильинский
источник
8
Что вы имеете в виду "использовать сам объект формы"? Когда у вас есть объект формы, какой метод вы используете для доступа к определенному элементу?
Сет
2
Я имею в виду, что я бы рекомендовал использовать N5 (document.getElementById ('myForm'). Elements.foo) для доступа к именованным элементам и N6 (document.getElementById ('myForm'). Elements) для доступа к итерируемой коллекции элементов
Сергей Ильинский
Я определяю стиль своего кода ... и в качестве предпочтения я придерживаюсь идентификаторов ... таким образом, доступ к элементам одинаков на всей странице. + другие упомянутые причины.
1
Почему рекомендуется обращаться к форме с помощью getElementID? почему document.myForm не работает? (У меня есть ситуация, когда это не работает, и мне интересно, почему)
Spundun
Привет, Спандун, ты, вероятно, решил свою проблему несколько месяцев назад (или, может быть, поднял руки :)), но в случае, если тебе было интересно, это, вероятно, было связано с тем, что ты не предоставил свой HTML-элемент формы с атрибутом «name».
Шелдон Р.
8

Я предпочитаю 5-й метод. То есть
[5] Используйте специальный идентификатор JavaScript , это , чтобы передать форму или поле объекта в функции от обработчика событий.

В частности, для форм:

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

и

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

Используя эту технику, функция никогда не должна знать
- порядок, в котором формы определены на странице,
- идентификатор формы, или
- имя формы

Аналогично для полей:

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

и

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;
}

В этом случае функция никогда не должна знать имя или идентификатор определенного поля веса, хотя она должна знать имя поля ограничения веса.

Робин Ричмонд
источник
Не уверен, что является основной причиной, но у меня был такой подход, возвращающий пустые строки в некоторых, но не во всех обстоятельствах.
Джейкоб Ли
7

Это не совсем ответ на ваш вопрос, но только в этой части:

[3] требует и идентификатор, и имя ... наличие обоих несколько избыточно

Скорее всего id, вам все равно понадобится атрибут для каждого поля формы, чтобы вы могли связать <label>с ним его элемент, например так:

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

Это необходимо для доступности (т. Е. Если вы не связываете ярлыки форм и элементы управления, почему вы так ненавидите слепых?).

Это несколько избыточно, хотя в меньшей степени, когда у вас есть флажки / переключатели, где некоторые из них могут совместно использовать name. В конечном счете, idи nameдля разных целей, даже если для обоих часто установлено одинаковое значение.

Пол Д. Уэйт
источник
5
Если вы вводите вход в метку, вам не нужен идентификатор или атрибут for. <label> Foo: <input type = "text" name = "foo" </ label>
kennebec
3
Очень верно, хотя это ограничивает то, что вы можете достичь с точки зрения внешнего вида.
Пол Д. Уэйт
2
@ kennebec - вы всегда должны использовать идентификатор, если хотите, чтобы метка была связана с элементом. В старых версиях IE (<8?) Элементы внутри метки не ассоциировались с меткой, если они не соответствовали атрибутам for и id .
RobG
В дополнение к тому, что написал @kennebec, использование идентификаторов создает глобальные JS-символы и их следует избегать.
mikemaccana
1
@mikemaccana: я видел проблемы с этим раньше. Я действительно думаю, что если ваши идентификаторы достаточно наглядны, а JavaScript имеет разумное пространство имен, это вряд ли вызовет проблемы.
Пол Д. Уэйт
6

Это немного устарело, но я хочу добавить кое-что, что я считаю актуальным.
(Я хотел прокомментировать один или два потока выше, но мне кажется, что мне нужна репутация 50, и у меня есть только 21 на момент, когда я пишу это. :))
Просто хочу сказать, что бывают ситуации, когда гораздо лучше получить доступ к элементы формы по имени, а не по идентификатору. Я не говорю о самой форме. Форма, хорошо, вы можете дать ему идентификатор, а затем получить к нему доступ по нему. Но если у вас есть переключатель в форме, гораздо проще использовать его как отдельный объект (получить и установить его значение), и, насколько я знаю, вы можете делать это только по имени.

Пример:

<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>

Вы можете получить / установить проверенное значение переключателя R1 в целом, используя
document.mainForm.R1.value
или
document.getElementById ("mainForm"). R1.value
Итак, если вы хотите использовать унитарный стиль, вы можете хочу всегда использовать этот метод, независимо от типа элемента формы. Я, мне очень удобно получать доступ к переключателям по имени и по текстовым полям по идентификатору.

VSIM
источник
То, что работает, - document.forms.mainForm.R1.valueэто действительно хороший способ избежать использования уродливого и утомительного типаdocument.getElementById()
Кай Карвер
2

Будучи старомодным, я всегда использовал синтаксис document.myform.myvar, но недавно обнаружил, что он не работает в Chrome (нормально в Firefox и IE). Это была страница Ajax (то есть загруженная в свойство innerHTML элемента div). Возможно, Chrome не распознал форму как элемент основного документа. Вместо этого я использовал getElementById (без ссылки на форму), и он работал нормально.

Капитан немо
источник
Вы можете просто вставить .forms, так что document.forms.myform.myvar
Кай Карвер
1

Просто чтобы добавить ко всему уже сказанному, вы можете получить доступ к inputs либо с помощью, nameлибо idиспользуя предпочтительно elementsсвойство формы Object, потому что без него вы можете получить свойство формы с именем "foo", а не элемент HTML. И, по словам Пола Д. Уэйта, совершенно нормально иметь как имя, так и идентификатор.

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>

Согласно MDN на странице HTMLFormElement.elements

Элементы свойства HTMLFormElement возвращают HTMLFormControlsCollection, в котором перечислены все элементы управления формы, содержащиеся в элементе. Независимо от этого вы можете получить только количество элементов управления формы, используя свойство length.

Вы можете получить доступ к определенному управлению формами в возвращенной коллекции с использованием либо индекса или элементом имени или идентификатора .

Жоао Пиментел Феррейра
источник
1

nameполе работает хорошо. Это дает ссылку на elements.

parent.children- Перечислит все элементы с полем имени родителя. parent.elements- перечислю только form elementsтакие какinput-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>

Примечание: .elementsчтобы работать, parentнужно быть <form> tag. Принимая во внимание, что .childrenбудет работать на любом HTML-element- например,<div>, <span>, etc .

Удачи...

Акаша
источник
0

Форма 2 в порядке, и форма 3 также рекомендуется.
Избыточность между name и id вызвана необходимостью сохранять совместимость, в html 5 некоторые элементы (такие как img, form, iframe и т. Д.) Потеряют свой атрибут «name», и рекомендуется использовать только их id, чтобы ссылаться на них с этого момента на :)

Wintermute
источник
Кажется, элементы ввода никогда не потеряют свой атрибут name из-за того, как он используется языками на стороне сервера. Таким образом, остается вопрос: что такое совместимый со стандартами метод, если у вас установлен только атрибут name?
Сет
В разработке, соответствующей стандартам, у вас не будет только названия, для начала. Если вы действительно не можете иметь ID, то я бы предложил функцию document.getElementByName ().
Wintermute
0

В дополнение к другим ответам document.myForm.foo - это так называемый уровень DOM 0, который реализуется Netscape и, таким образом, на самом деле не является открытым стандартом, хотя он поддерживается большинством браузеров.

Кент Тонг
источник
4
Доступ к формам и элементам управления форм по имени, идентификатору и индексу является частью стандарта DOM 2 HTML для коллекций HTML .
RobG
0

Проверьте эту страницу: https://developer.mozilla.org/En/DOM/Document.getElementsByName

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

Это должны быть «элементы» и они должны возвращать массив, потому что более одного элемента могут иметь одно и то же имя.

Роберт
источник
@ Роберт, я теперь думаю, что это может быть хорошим решением, хотя это прямо из документов заставило меня нервничать: «Этот метод может быть сомнительным для использования, учитывая вышеуказанные изменения между типами документов и текущим нестандартным поведением для этого метод в XHTML. "
Сет
Всем привет. Какая документация предложена против этого? Я думаю, что если вы используете xhtml во всех средах DOM, в которых вы работаете, то все будет в порядке. Кроме того, какие браузеры не поддерживают это? Вот документы для IE: msdn.microsoft.com/en-us/library/ms536438(VS.85).aspx В дополнение к Mozilla выше, кто еще может не поддерживать его?
Роберт
0

Мой ответ будет отличаться от точного вопроса. Если я хочу получить доступ к определенному элементу, я буду использовать document.getElementById (). Примером является вычисление полного имени человека, поскольку оно основано на нескольких полях, но это повторяемая формула.

Если я хочу получить доступ к элементу как части функциональной структуры (формы), я буду использовать:

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

Вот как это работает с точки зрения бизнеса. Изменения в цикле сопровождаются функциональными изменениями в приложении и имеют для них смысл. Я применяю его в основном для удобной проверки и предотвращения сетевых вызовов для проверки неверных данных. Я повторяю проверку на стороне сервера (и добавляю еще кое-что к ней), но если я могу помочь клиентской части пользователя, то это выгодно всем.

Для агрегирования данных (например, построение круговой диаграммы на основе данных в форме) я использую документы конфигурации и пользовательские объекты Javascript. Тогда точное значение поля важно по отношению к его контексту, и я использую document.getElementById ().

Люк Бергман
источник
0

Потому что дело [2] document.myForm.fooявляется диалектом из Internet Exploere. Так что вместо этого я предпочитаю document.forms.myForm.elements.fooили document.forms["myForm"].elements["foo"].

Такахар Танак
источник
-1

Я предпочитаю этот

document.forms['idOfTheForm'].nameOfTheInputFiled.value;
Фахим Мд. Риаз
источник
2
Добро пожаловать в ТАК, мы ценим ваш вклад. Пожалуйста, отредактируйте свой ответ и объясните, почему и как.
B -