Encontre o rótulo html associado a uma determinada entrada

110

Digamos que eu tenha um formulário html. Cada input / select / textarea terá um correspondente <label>com o foratributo definido para o id de seu companheiro. Nesse caso, sei que cada entrada terá apenas um rótulo.

Dado um elemento de entrada em javascript - por meio de um evento onkeyup, por exemplo - qual é a melhor maneira de encontrar seu rótulo associado?

Joel Coehoorn
fonte
5
Observe que um elemento pode ter mais de um rótulo, já vi alguns aplicativos (SAP para um) que têm vários rótulos por elemento.
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 };
Alan Wells,
ou apenas node.parentNode.querySelector ("label [for = '" + node.id + "']"). innerHTML; lol
Solomon P Byer

Respostas:

87

Primeiro, examine a página em busca de rótulos e atribua uma referência ao rótulo do elemento real do formulário:

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

Então, você pode simplesmente ir:

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

Não há necessidade de uma matriz de pesquisa :)

FlySwat
fonte
Você pode explicar onde o seu uso de uma propriedade expando difere do meu? Eu não uso nenhum "array de pesquisa", eu uso um objeto com propriedades. Há apenas diferença sintática entre "element.label", "element ['label']" ou "lookup ['elementId']". Nos bastidores, eles são a mesma coisa .
Tomalak
4
Isso é melhor porque não tenho que manter um objeto separado por perto - o relacionamento é armazenado com o elemento de entrada diretamente.
Joel Coehoorn
3
Isso deve ser tratado pelo navegador
andho
103

Se você estiver usando jQuery, você pode fazer algo assim

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

Se você não estiver usando jQuery, você terá que pesquisar o rótulo. Aqui está uma função que recebe o elemento como um argumento e retorna o rótulo associado

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

Existe uma labelspropriedade no padrão HTML5 que aponta para rótulos associados a um elemento de entrada.

Então, você poderia usar algo assim (suporte para labelspropriedade nativa , mas com um substituto para recuperar rótulos caso o navegador não seja compatível) ...

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

Ainda mais fácil se você estiver usando 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;
};
alex
fonte
4
Não apenas no Chrome, ele está no padrão HTML5 .
Bergi
1
Isso deve ser waaaay up. Obrigado!
maxhm10
23

Estou um pouco surpreso que ninguém pareça saber que você está perfeitamente autorizado a fazer:

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

Que não são apanhados por qualquer uma das respostas sugeridas, mas vai rotular a entrada corretamente.

Aqui está um código que leva esse caso em consideração:

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

Uso:

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

Algumas notas:

  • O código foi escrito para maior clareza, não para desempenho. Mais alternativas de desempenho podem estar disponíveis.
  • Este código suporta a obtenção de rótulos de vários itens de uma vez. Se não é isso que você quer, adapte conforme necessário.
  • Isso ainda não resolve coisas como aria-labelledbyse você fosse usar isso (deixado como um exercício para o leitor).
  • Usar vários rótulos é um negócio complicado quando se trata de suporte em diferentes agentes de usuário e tecnologias assistivas, então teste bem e use por sua própria conta e risco, etc.
  • Sim, você também pode implementar isso sem usar jQuery. :-)
Gijs
fonte
6
É bom ver alguém mencionando uma associação de rótulo implícita em vez de fazer uma suposição de que sempre haverá um foratributo no labelelemento.
Josh Habdas,
14

Anteriormente ...

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

Mais tarde...

var myLabel = lookup[myInput.id];

Comentário Snarky: Sim, você também pode fazer isso com JQuery. :-)

Tomalak
fonte
1
Agradável. Vou refatorar isso um pouco para que crie a pesquisa na primeira vez que chamo o método, mas deve funcionar.
Joel Coehoorn
Insinuei que você construiria a pesquisa apenas uma vez.
Tomalak
Esteja ciente de que houve um pequeno erro: use a propriedade "htmlFor", não "for", pois esta última é uma palavra reservada em JS. Costumo esquecer que ao usar objetos de rótulo ... :-)
Tomalak
Eu tenho uma maneira de fazer isso sem uma matriz de pesquisa acima.
FlySwat
Eu quis dizer mover o código init dentro do método, não apenas uma vez :(
Joel Coehoorn
13

document.querySelector ("label [for =" + vHtmlInputElement.id + "]");

Isso responde à pergunta da maneira mais simples e enxuta. Este usa javascript vanilla e funciona em todos os navegadores adequados.

Luigi D'Amico
fonte
Isso não fornece uma resposta para a pergunta. Assim que tiver reputação suficiente, você poderá comentar qualquer postagem ; em vez disso, forneça respostas que não exijam esclarecimentos do autor da pergunta . - Da avaliação
loki
1
Isso definitivamente fornece uma resposta para a pergunta @loki. Só porque não há nenhuma explicação adicional para isso, não significa que esteja errado ou não tenha tentado respondê-la.
geisterfurz007
A resposta mais simples e útil! Obrigado!
iedmrc
8

com jquery você poderia fazer algo como

var nameOfLabel = someInput.attr('id');
var label = $("label[for='" + nameOfLabel + "']");
AndreasKnudsen
fonte
Rótulos potencialmente perdidos, embora sejam ancestrais.
alex de
4

Se você deseja usar o querySelector (e pode, mesmo no IE9 e às vezes no IE8!), Outro método se torna viável.

Se o campo do seu formulário tiver um ID e você usar o foratributo do rótulo , isso se torna muito simples no JavaScript moderno:

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

Alguns notaram sobre vários rótulos; se todos eles usarem o mesmo valor para o foratributo, basta usar em querySelectorAllvez de querySelectore fazer um loop para obter tudo o que você precisa.

Brendan
fonte
2
$("label[for='inputId']").text()

Isso me ajudou a obter o rótulo de um elemento de entrada usando seu ID.

haifacarina
fonte
2

A resposta de Gijs foi muito valiosa para mim, mas infelizmente a extensão não funciona.

Esta é uma extensão reescrita que funciona, pode ajudar alguém:

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

Todas as outras respostas estão extremamente desatualizadas !!

Tudo o que tem a fazer é:

input.labels

O HTML5 é suportado por todos os principais navegadores há muitos anos. Não há absolutamente nenhuma razão para você ter que fazer isso do zero por conta própria ou polyfill! Literalmente, basta usar input.labelse resolverá todos os seus problemas.

dj nag
fonte
1
De acordo com esta página , input.labelsnão é compatível com IE ou Edge, e o Firefox apenas adicionou o suporte.
Antti29 de
@ Antti29 Você pode adicionar a funcionalidade usando um shim: github.com/termi/ES5-DOM-SHIM Você pode ver o recurso sendo adicionado aqui: github.com/termi/ES5-DOM-SHIM/blob/…
ADJenks
2

Uma solução realmente concisa usando recursos ES6 como desestruturação e retornos implícitos para transformá-lo em um revestimento prático seria:

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

Ou simplesmente obter um rótulo, não um NodeList:

const getFirstLabel = ({ labels, id }) => labels && labels[0] || document.querySelector(`label[for=${id}]`)
StateOfTheArtJonas
fonte
1

Na verdade, é muito mais fácil adicionar um id ao rótulo no próprio formulário, por exemplo:

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

Então, você pode simplesmente usar algo assim:

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

O javascript precisa estar em uma função body onload para funcionar.

Apenas um pensamento, funciona perfeitamente para mim.

Martie Henry
fonte
1

Como já foi mencionado, a resposta (atualmente) mais bem avaliada não leva em consideração a possibilidade de inserir uma entrada dentro de um rótulo.

Como ninguém postou uma resposta sem JQuery, aqui está a minha:

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

Neste exemplo, por questão de simplicidade, a tabela de pesquisa é indexada diretamente pelos elementos HTML de entrada. Isso dificilmente é eficiente e você pode adaptá-lo como quiser.

Você pode usar um formulário como elemento base ou o documento inteiro se quiser obter rótulos para vários formulários de uma vez.

Nenhuma verificação é feita para HTML incorreto (entradas múltiplas ou ausentes dentro dos rótulos, entrada ausente com o id htmlFor correspondente, etc), mas sinta-se à vontade para adicioná-los.

Você pode querer cortar os textos do rótulo, uma vez que espaços à direita geralmente estão presentes quando a entrada é incorporada ao rótulo.

Kuroi Neko
fonte
1

A melhor resposta funciona perfeitamente bem, mas na maioria dos casos, é um exagero e ineficiente percorrer todos os labelelementos.

Aqui está uma função eficiente para obter o labelque vai com o inputelemento:

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

Para mim, esta única linha de código foi suficiente:

el = document.getElementById(id).previousElementSibling;

Na maioria dos casos, o labelestará muito próximo ou próximo à entrada, o que significa que o loop na função acima só precisa iterar um número muito pequeno de vezes.

Dan Bray
fonte
0

você tentou usar document.getElementbyID ('id') onde id é o id do rótulo ou é a situação em que você não sabe qual deles está procurando

Josh Mein
fonte
Eu sei a id do elemento de entrada, mas não a id do rótulo.
Joel Coehoorn
você não pode definir um id correspondente para o rótulo, como input id = 'test' e label id = 'lbl_test "
Josh Mein
0

Use um seletor JQuery:

$("label[for="+inputElement.id+"]")
Mike McKay
fonte
0

Para futuros pesquisadores ... O seguinte é uma versão jQuery-ified da resposta aceita de 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]));   
        }
    }
}

Usando:

$("#myFormElemId").data("label").css("border","3px solid red");
Tipo de objeto
fonte
+1, mas pelo que vejo não há razão para usar a versão jQuery para o primeiro bloco: não é mais curto ou mais legível, e o javascript simples provavelmente terá um desempenho melhor. É bom ter um exemplo de jQuery sobre como usá-lo depois de criado, no entanto.
Joel Coehoorn
Obviamente, para muitos de nós não há uma razão técnica para essa abordagem, mas uma razão, pelo menos no meu caso, é de RH. Imagine que você tem uma equipe que inclui designers, integradores e até mesmo desenvolvedores Jr que você está acostumando a usar jQuery. Manter as coisas no paradigma jQuery pode ajudar a manter a produtividade alta e reduzir a frustração.
ObjectType de
Isso não é muito jQuery-ified . Por que o forloop acabou each()? Por que o em htmlForvez de attr("for")?
alex
Depende da perspectiva, eu acho. O consumo foi jQuery-ified, não os internos.
ObjectType de
0

Eu sei que isso é antigo, mas tive problemas com algumas soluções e juntei as peças. Eu testei isso no Windows (Chrome, Firefox e MSIE) e OS X (Chrome e Safari) e acredito que esta é a solução mais simples. Funciona com estes três estilos de fixação de etiqueta.

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

Usando jQuery:

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

Meu JSFiddle: http://jsfiddle.net/pnosko/6PQCw/

Peter Nosko
fonte
Na verdade, isso não está funcionando - está apenas retornando o texto do elemento pai, que às vezes é o texto que você deseja.
John Hascall de
0

Eu fiz para minha própria necessidade, pode ser útil para alguém: 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
fonte
0

Estou um pouco surpreso por ninguém estar sugerindo o uso do método de relacionamento CSS.

em uma folha de estilo, você pode fazer referência a um rótulo do seletor de elemento:

<style>

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

</style>

se a caixa de seleção tiver um id 'XXX', o rótulo será encontrado por meio do jQuery por:

$('#XXX + label');

Você também pode aplicar .find ('+ rótulo') para retornar o rótulo de um elemento de caixa de seleção jQuery, ou seja, útil durante o loop:

$('input[type=checkbox]').each( function(){
   $(this).find('+ label');
});
Gordon Rouse
fonte
Opa, devo observar que isso depende do rótulo vindo diretamente após o elemento.
Gordon Rouse