Найти метку html, связанную с заданным вводом

110

Допустим, у меня есть html-форма. Каждый вход / выбрать / текстовое поле будет иметь соответствующий <label>с forнабором атрибутов идентификатора это компаньон. В этом случае я знаю, что у каждого входа будет только одна метка.

Учитывая элемент ввода в javascript - например, через событие onkeyup - как лучше всего найти связанный с ним ярлык?

Джоэл Кохорн
источник
5
Обратите внимание, что у элемента может быть несколько меток, я видел некоторые приложения (например, SAP), у которых есть несколько меток на элемент.
Motti
2
function getInputLabel(thisElement) { var theAssociatedLabel,elementID; elementID = thisElement.id; theAssociatedLabel = thisElement.parentNode.querySelector("label[for='" + elementID + "']"); console.log('theAssociatedLabel.htmlFor: ' + theAssociatedLabel.htmlFor); theAssociatedLabel.style.backgroundColor = "green";//Set the label background color to green };
Алан Уэллс
или просто node.parentNode.querySelector ("label [for = '" + node.id + "']"). innerHTML; lol
Соломон П Байер

Ответы:

88

Сначала просканируйте страницу на предмет ярлыков и назначьте ссылку на ярлык из фактического элемента формы:

var labels = document.getElementsByTagName('LABEL');
for (var i = 0; i < labels.length; i++) {
    if (labels[i].htmlFor != '') {
         var elem = document.getElementById(labels[i].htmlFor);
         if (elem)
            elem.label = labels[i];         
    }
}

Затем вы можете просто перейти:

document.getElementById('MyFormElem').label.innerHTML = 'Look ma this works!';

Нет необходимости в поисковом массиве :)

FlySwat
источник
Можете ли вы объяснить, чем ваше использование свойства expando отличается от моего? Я не использую никакого "массива поиска", я использую объект со свойствами. Существует только синтаксическая разница между «element.label», «element ['label']» или «lookup ['elementId']». За кадром это одно и то же .
Tomalak
4
Это лучше, потому что мне не нужно держать вокруг отдельный объект - связь сохраняется непосредственно с элементом ввода.
Joel Coehoorn
3
Это должно выполняться браузером
andho
104

Если вы используете jQuery, вы можете сделать что-то вроде этого

$('label[for="foo"]').hide ();

Если вы не используете jQuery, вам придется искать метку. Вот функция, которая принимает элемент в качестве аргумента и возвращает связанную метку

function findLableForControl(el) {
   var idVal = el.id;
   labels = document.getElementsByTagName('label');
   for( var i = 0; i < labels.length; i++ ) {
      if (labels[i].htmlFor == idVal)
           return labels[i];
   }
}
TonyB
источник
33

В стандарте HTML5 есть labelsсвойство, которое указывает на метки, связанные с элементом ввода.

Итак, вы можете использовать что-то вроде этого (поддержка собственного labelsсвойства, но с резервным вариантом для получения меток на случай, если браузер не поддерживает его) ...

var getLabelsForInputElement = function(element) {
    var labels = [];
    var id = element.id;

    if (element.labels) {
        return element.labels;
    }

    id && Array.prototype.push
        .apply(labels, document.querySelector("label[for='" + id + "']"));

    while (element = element.parentNode) {
        if (element.tagName.toLowerCase() == "label") {
            labels.push(element);
        }  
    }

    return labels;
};

// ES6
var getLabelsForInputElement = (element) => {
    let labels;
    let id = element.id;

    if (element.labels) {
        return element.labels;
    }

    if (id) {
        labels = Array.from(document.querySelector(`label[for='${id}']`)));
    }

    while (element = element.parentNode) {
        if (element.tagName.toLowerCase() == "label") {
            labels.push(element);
        }  
    }

    return labels;
};

Еще проще, если вы используете jQuery ...

var getLabelsForInputElement = function(element) {
    var labels = $();
    var id = element.id;

    if (element.labels) {
        return element.labels;
    }

    id && (labels = $("label[for='" + id  + "']")));

    labels = labels.add($(element).parents("label"));

    return labels;
};
Алекс
источник
4
Не только в Chrome, это стандарт HTML5 .
Bergi
1
Это должно быть скоро. Спасибо!
maxhm10
23

Я немного удивлен, что, кажется, никто не знает, что вам вполне разрешено :

<label>Put your stuff here: <input value="Stuff"></label>

Который не подхватит ни один из предложенных ответов, но будет правильно маркировать вход.

Вот код, который учитывает этот случай:

$.fn.getLabels = function() {
    return this.map(function() {
        var labels = $(this).parents('label');
        if (this.id) {
            labels.add('label[for="' + this.id + '"]');
        }
        return labels.get();
    });
};

Использование:

$('#myfancyinput').getLabels();

Некоторые примечания:

  • Код был написан для ясности, а не для производительности. Могут быть доступны более производительные альтернативы.
  • Этот код поддерживает получение меток нескольких элементов за один раз. Если это не то, что вы хотите, при необходимости адаптируйте.
  • Это по-прежнему не заботится о таких вещах, как aria-labelledby если бы вы использовали это (оставлено в качестве упражнения для читателя).
  • Использование нескольких ярлыков - сложный бизнес, когда речь идет о поддержке различных пользовательских агентов и вспомогательных технологий, поэтому хорошо тестируйте и используйте на свой страх и риск и т. Д. И т. Д.
  • Да, вы также можете реализовать это без использования jQuery. :-)
Gijs
источник
6
Приятно видеть, что кто-то поднимает неявную ассоциацию меток, а не делает предположение, что forатрибут в labelэлементе всегда будет .
Джош Хабдас
14

Ранее...

var labels = document.getElementsByTagName("LABEL"),
    lookup = {},
    i, label;

for (i = 0; i < labels.length; i++) {
    label = labels[i];
    if (document.getElementById(label.htmlFor)) {
        lookup[label.htmlFor] = label;
    }
}

Потом...

var myLabel = lookup[myInput.id];

Язвительный комментарий: Да, вы также можете сделать это с помощью JQuery. :-)

Томалак
источник
1
Ницца. Я немного реорганизую его, чтобы он создавал поиск при первом вызове метода, но он должен помочь.
Joel Coehoorn
Я имел в виду, что вы создадите поиск только один раз.
Tomalak
Имейте в виду, что в нем была небольшая ошибка: используйте свойство «htmlFor», а не «for», поскольку последнее является зарезервированным словом в JS. Я часто забываю, что при использовании объектов меток ... :-)
Tomalak
У меня есть способ сделать это без массива поиска выше.
FlySwat
Я имел в виду переместить код инициализации внутри метода, а не делать это только один раз :(
Джоэл Кохорн,
13

document.querySelector ("метка [для =" + vHtmlInputElement.id + "]");

Это дает самый простой и краткий ответ на вопрос. Это использует ванильный javascript и работает во всех основных браузерах.

Луиджи Д'Амико
источник
Это не дает ответа на вопрос. Как только у вас будет достаточная репутация, вы сможете комментировать любой пост ; вместо этого предоставьте ответы, которые не требуют пояснений от спрашивающего . - Из
loki
1
Это определенно дает ответ на вопрос @loki. Просто потому, что для этого нет дополнительных объяснений, это не значит, что он неправильный или не пытался ответить на него.
geisterfurz007
Самый простой и полезный ответ! Спасибо!
iedmrc
8

с jquery вы можете сделать что-то вроде

var nameOfLabel = someInput.attr('id');
var label = $("label[for='" + nameOfLabel + "']");
Андреас Кнудсен
источник
Потенциально пропускает ярлыки, которые являются предками.
Alex
4

Если вы хотите использовать querySelector (а можете даже до IE9, а иногда и до IE8!), Другой метод становится жизнеспособным.

Если у вашего поля формы есть идентификатор, и вы используете forатрибут label , это становится довольно просто в современном JavaScript:

var form = document.querySelector('.sample-form');
var formFields = form.querySelectorAll('.form-field');

[].forEach.call(formFields, function (formField) {
    var inputId = formField.id;
    var label = form.querySelector('label[for=' + inputId + ']');
    console.log(label.textContent);
});

Некоторые отметили несколько ярлыков; если все они используют одно и то же значение для forатрибута, просто используйте querySelectorAllвместо querySelectorи выполните цикл, чтобы получить все, что вам нужно.

Брендан
источник
3

Все остальные ответы сильно устарели !!

Все, что вам нужно сделать, это:

input.labels

HTML5 уже много лет поддерживается всеми основными браузерами. Нет абсолютно никаких причин, по которым вам придется делать это с нуля самостоятельно или заполнять его полифиллами! Буквально просто используйте, input.labelsи он решит все ваши проблемы.

диджей наг
источник
1
Согласно этой странице , input.labelsне поддерживается IE или Edge, а Firefox только что добавил поддержку.
Antti29
@ Antti29 Вы можете добавить функциональность с помощью прокладки: github.com/termi/ES5-DOM-SHIM Вы можете увидеть добавляемую функцию здесь: github.com/termi/ES5-DOM-SHIM/blob/…
ADJenks,
2
$("label[for='inputId']").text()

Это помогло мне получить метку элемента ввода по его идентификатору.

Хайфакарина
источник
2

Ответ от Gijs был для меня самым ценным, но, к сожалению, расширение не работает.

Вот переписанное расширение, которое работает, может кому-то помочь:

jQuery.fn.getLabels = function () {
    return this.map(function () {
        var parentLabels = $(this).parents('label').get();
        var associatedLabels = this.id ? associatedLabels = $("label[for='" + this.id + "']").get() : [];
        return parentLabels.concat(associatedLabels);
    });
};
OzrenTkalcecKrznaric
источник
2

Действительно краткое решение, использующее такие функции ES6, как деструктуризация и неявный возврат, чтобы превратить его в удобный однострочный лайнер, будет:

const getLabels = ({ labels, id }) => labels || document.querySelectorAll(`label[for=${id}]`)

Или просто получить одну метку, а не NodeList:

const getFirstLabel = ({ labels, id }) => labels && labels[0] || document.querySelector(`label[for=${id}]`)
StateOfTheArtJonas
источник
1

На самом деле гораздо проще добавить идентификатор к метке в самой форме, например:

<label for="firstName" id="firstNameLabel">FirstName:</label>

<input type="text" id="firstName" name="firstName" class="input_Field" 
       pattern="^[a-zA-Z\s\-]{2,25}$" maxlength="25"
       title="Alphabetic, Space, Dash Only, 2-25 Characters Long" 
       autocomplete="on" required
/>

Затем вы можете просто использовать что-то вроде этого:

if (myvariableforpagelang == 'es') {
   // set field label to spanish
   document.getElementById("firstNameLabel").innerHTML = "Primer Nombre:";
   // set field tooltip (title to spanish
   document.getElementById("firstName").title = "Alfabética, espacio, guión Sólo, 2-25 caracteres de longitud";
}

Для работы javascript должен быть включен в функцию загрузки тела.

Просто мысль прекрасно работает на меня.

Марти Генри
источник
1

Как уже упоминалось, ответ (на данный момент) с самым высоким рейтингом не учитывает возможность встраивания ввода внутри метки.

Поскольку никто не опубликовал ответ без JQuery, вот мой:

var labels = form.getElementsByTagName ('label');
var input_label = {};
for (var i = 0 ; i != labels.length ; i++)
{
    var label = labels[i];
    var input = label.htmlFor
              ? document.getElementById(label.htmlFor)
              : label.getElementsByTagName('input')[0];
    input_label[input.outerHTML] = 
        (label.innerText || label.textContent); // innerText for IE8-
}

В этом примере для простоты поисковая таблица напрямую индексируется входными элементами HTML. Это вряд ли эффективно, и вы можете адаптировать его по своему усмотрению.

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

Никаких проверок на неправильный HTML (множественные или отсутствующие входные данные внутри меток, отсутствующие входные данные с соответствующим htmlFor id и т. Д.) Не производятся, но вы можете их добавить.

Возможно, вы захотите обрезать текст меток, так как конечные пробелы часто присутствуют, когда ввод встроен в метку.

курои неко
источник
1

Лучший ответ работает отлично, но в большинстве случаев перебирать все labelэлементы излишне и неэффективно .

Вот эффективная функция для получения того, labelчто идет с inputэлементом:

function getLabelForInput(id)
{
    var el = document.getElementById(id);
    if (!el)
        return null;
    var elPrev = el.previousElementSibling;
    var elNext = el.nextElementSibling;
    while (elPrev || elNext)
    {
        if (elPrev)
        {
            if (elPrev.htmlFor === id)
                return elPrev;
            elPrev = elPrev.previousElementSibling;
        }
        if (elNext)
        {
            if (elNext.htmlFor === id)
                return elNext;
            elNext = elNext.nextElementSibling;
        }
    }
    return null;
}

Для меня этой одной строчки кода было достаточно:

el = document.getElementById(id).previousElementSibling;

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

Дэн Брэй
источник
0

пробовали ли вы использовать document.getElementbyID ('id'), где id - это идентификатор метки или ситуация, когда вы не знаете, какой из них вы ищете

Джош Майн
источник
Я знаю идентификатор входного элемента, но не идентификатор метки.
Joel Coehoorn
не можете ли вы установить соответствующий идентификатор для метки, например input id = 'test' и label id = 'lbl_test "
Джош Майн,
0

Используйте селектор JQuery:

$("label[for="+inputElement.id+"]")
Майк Маккей
источник
0

Для будущих искателей ... Ниже приводится jQuery-версия принятого ответа FlySwat:

var labels = $("label");
for (var i = 0; i < labels.length; i++) {
    var fieldId = labels[i].htmlFor;
    if (fieldId != "") {
        var elem = $("#" + fieldId);
        if (elem.length != 0) {
            elem.data("label", $(labels[i]));   
        }
    }
}

С помощью:

$("#myFormElemId").data("label").css("border","3px solid red");
ObjectType
источник
+1, но из того, что я вижу, нет причин использовать версию jQuery для первого блока: она не короче и не читабельнее, а простой javascript, вероятно, будет работать лучше. Тем не менее, приятно иметь пример jQuery того, как его использовать после создания.
Джоэл Коэхорн
Очевидно, для многих из нас нет особой технической причины для такого подхода, скорее причина, по крайней мере, в моем случае, связана с HR. Представьте, что у вас есть команда, в которую входят дизайнеры, интеграторы и даже младшие разработчики, которые, по вашему мнению, привыкли использовать jQuery. Использование парадигмы jQuery может помочь повысить производительность и уменьшить разочарование.
ObjectType
Это не очень похоже на jQuery . Почему forпетля закончилась each()? Почему htmlForвместо attr("for")?
Alex
Полагаю, это зависит от перспективы. Потребление было jQuery-ified, а не внутренним.
ObjectType 06
0

Я знаю, что это устарело, но у меня были проблемы с некоторыми решениями, и я собрал все вместе. Я тестировал это в Windows (Chrome, Firefox и MSIE) и OS X (Chrome и Safari) и считаю, что это самое простое решение. Он работает с этими тремя стилями прикрепления этикеток.

<label><input type="checkbox" class="c123" id="cb1" name="item1">item1</label>

<input type="checkbox" class="c123" id="cb2" name="item2">item2</input>

<input type="checkbox" class="c123" id="cb3" name="item3"><label for="cb3">item3</label>

Используя jQuery:

$(".c123").click(function() {
    $cb = $(this);
    $lb = $(this).parent();
    alert( $cb.attr('id') + ' = ' + $lb.text() );
});

Мой JSFiddle: http://jsfiddle.net/pnosko/6PQCw/

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

Я сделал для себя, может кому-то пригодится: JSFIDDLE

$("input").each(function () {
    if ($.trim($(this).prev('label').text()) != "") {
        console.log("\nprev>children:");
        console.log($.trim($(this).prev('label').text()));
    } else {
        if ($.trim($(this).parent('label').text()) != "") {
            console.log("\nparent>children:");
            console.log($.trim($(this).parent('label').text()));
        } else {
            if ($.trim($(this).parent().prev('label').text()) != "") {
                console.log("\nparent>prev>children:");
                console.log($.trim($(this).parent().prev('label').text()));
            } else {
                console.log("NOTFOUND! So set your own condition now");
            }
        }
    }
});
Itsazzad
источник
0

Я немного удивлен, что никто не предлагает использовать метод отношений CSS?

в таблице стилей вы можете ссылаться на метку из селектора элементов:

<style>

//for input element with class 'YYY'
input.YYY + label {}

</style>

если у флажка есть идентификатор «XXX», тогда ярлык будет найден через jQuery по:

$('#XXX + label');

Вы также можете применить .find ('+ label'), чтобы вернуть метку из элемента флажка jQuery, то есть полезно при цикле:

$('input[type=checkbox]').each( function(){
   $(this).find('+ label');
});
Гордон Роуз
источник
К сожалению, я должен отметить, что это зависит от метки, идущей непосредственно после элемента.
Гордон Роуз