Rechercher l'étiquette html associée à une entrée donnée

110

Disons que j'ai un formulaire html. Chaque input / select / textarea aura une correspondance <label>avec l' forattribut défini sur l'id de son compagnon. Dans ce cas, je sais que chaque entrée n'aura qu'une seule étiquette.

Étant donné un élément d'entrée en javascript - via un événement onkeyup, par exemple - quelle est la meilleure façon de trouver son étiquette associée?

Joel Coehoorn
la source
5
Notez qu'un élément peut avoir plus d'une étiquette, j'ai vu certaines applications (SAP pour une) qui ont plusieurs étiquettes par élément.
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 simplement node.parentNode.querySelector ("label [for = '" + node.id + "']"). innerHTML; lol
Solomon P Byer

Réponses:

87

Tout d'abord, scannez la page à la recherche d'étiquettes et attribuez une référence à l'étiquette à partir de l'élément de formulaire réel:

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

Ensuite, vous pouvez simplement aller:

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

Pas besoin de tableau de recherche :)

FlySwat
la source
Pouvez-vous expliquer en quoi votre utilisation d'une propriété expando diffère de la mienne? Je n'utilise aucun "tableau de recherche", j'utilise un objet avec des propriétés. Il n'y a qu'une différence syntaxique entre "element.label", "element ['label']" ou "lookup ['elementId']". Dans les coulisses, c'est la même chose .
Tomalak
4
C'est plus agréable car je n'ai pas à garder un objet séparé autour - la relation est stockée directement avec l'élément d'entrée.
Joel Coehoorn
3
Cela devrait être géré par le navigateur
andho
103

Si vous utilisez jQuery, vous pouvez faire quelque chose comme ça

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

Si vous n'utilisez pas jQuery, vous devrez rechercher l'étiquette. Voici une fonction qui prend l'élément comme argument et renvoie l'étiquette associée

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
la source
33

Il existe une labelspropriété dans la norme HTML5 qui pointe vers des étiquettes associées à un élément d'entrée.

Vous pouvez donc utiliser quelque chose comme ça (prise en charge de la labelspropriété native mais avec une solution de secours pour récupérer les étiquettes au cas où le navigateur ne la prendrait pas en charge) ...

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

Encore plus facile si vous utilisez 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
la source
4
Non seulement dans Chrome, mais dans la norme HTML5 .
Bergi
1
Cela devrait être waaaay up. Merci!
maxhm10
23

Je suis un peu surpris que personne ne semble savoir que vous êtes parfaitement autorisé à faire:

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

Ce qui ne sera pas repris par l' une des réponses proposées, mais sera étiqueter correctement l'entrée.

Voici un code qui tient compte de ce cas:

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

Usage:

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

Quelques notes:

  • Le code a été écrit pour plus de clarté, pas pour les performances. Des alternatives plus performantes peuvent être disponibles.
  • Ce code prend en charge l'obtention des étiquettes de plusieurs éléments en une seule fois. Si ce n'est pas ce que vous voulez, adaptez-vous si nécessaire.
  • Cela ne prend toujours pas en compte les choses comme aria-labelledbysi vous deviez l'utiliser (laissé comme exercice au lecteur).
  • L'utilisation de plusieurs étiquettes est une entreprise délicate lorsqu'il s'agit de prendre en charge différents agents utilisateurs et technologies d'assistance, alors testez bien et utilisez à vos propres risques, etc. etc.
  • Oui, vous pouvez également implémenter cela sans utiliser jQuery. :-)
Gijs
la source
6
C'est bien de voir quelqu'un évoquer une association d'étiquettes implicite au lieu de supposer qu'il y aura toujours un forattribut sur l' labelélément.
Josh Habdas
14

Plus tôt...

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

Plus tard...

var myLabel = lookup[myInput.id];

Commentaire Snarky: Oui, vous pouvez également le faire avec JQuery. :-)

Tomalak
la source
1
Agréable. Je vais refactoriser cela juste un peu pour qu'il crée la recherche la première fois que j'appelle la méthode, mais cela devrait faire l'affaire.
Joel Coehoorn
J'ai laissé entendre que vous ne créeriez la recherche qu'une seule fois.
Tomalak
Sachez qu'il y avait une petite erreur dedans: utilisez la propriété "htmlFor", pas "for", car ce dernier est un mot réservé dans JS. J'ai tendance à oublier que lorsque
j'utilise des
J'ai un moyen de le faire sans tableau de recherche ci-dessus.
FlySwat
Je voulais dire déplacer le code d'initialisation dans la méthode, ne pas le faire une seule fois :(
Joel Coehoorn
13

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

Cela répond à la question de la manière la plus simple et la plus légère. Cela utilise du javascript vanille et fonctionne sur tous les navigateurs appropriés du flux principal.

Luigi D'Amico
la source
Cela ne répond pas à la question. Une fois que vous aurez une réputation suffisante, vous pourrez commenter n'importe quel message ; au lieu de cela, fournissez des réponses qui ne nécessitent pas de clarification de la part du demandeur . - De l'avis
loki
1
Cela fournit très certainement une réponse à la question @loki Ce n'est pas parce qu'il n'y a pas d'autre explication à cela que cela signifie que c'est faux ou que vous n'avez pas tenté d'y répondre.
geisterfurz007
La réponse la plus simple et la plus utile! Merci!
iedmrc
8

avec jquery vous pouvez faire quelque chose comme

var nameOfLabel = someInput.attr('id');
var label = $("label[for='" + nameOfLabel + "']");
AndreasKnudsen
la source
Manque potentiellement les étiquettes si ce sont des ancêtres.
alex
4

Si vous êtes prêt à utiliser querySelector (et vous le pouvez, même jusqu'à IE9 et parfois IE8!), Une autre méthode devient viable.

Si votre champ de formulaire a un identifiant et que vous utilisez l' forattribut de l'étiquette , cela devient assez simple dans JavaScript moderne:

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

Certains ont noté plusieurs étiquettes; s'ils utilisent tous la même valeur pour l' forattribut, utilisez simplement querySelectorAllau lieu de querySelectoret bouclez pour obtenir tout ce dont vous avez besoin.

Brendan
la source
3

Toutes les autres réponses sont extrêmement dépassées !!

Tout ce que tu dois faire est:

input.labels

HTML5 est déjà pris en charge par tous les principaux navigateurs depuis de nombreuses années. Il n'y a absolument aucune raison pour que vous deviez le faire vous-même à partir de zéro ou le polyfiller! Il suffit de l'utiliser littéralement input.labelset cela résout tous vos problèmes.

dj nag
la source
1
Selon cette page , input.labelsn'est pas pris en charge par IE ou Edge, et Firefox vient d'ajouter le support.
Antti29
@ Antti29 Vous pouvez ajouter la fonctionnalité à l'aide d'un shim: github.com/termi/ES5-DOM-SHIM Vous pouvez voir la fonctionnalité ajoutée ici: github.com/termi/ES5-DOM-SHIM/blob/…
ADJenks
2
$("label[for='inputId']").text()

Cela m'a aidé à obtenir l'étiquette d'un élément d'entrée en utilisant son ID.

haifacarina
la source
2

La réponse de Gijs a été la plus précieuse pour moi, mais malheureusement, l'extension ne fonctionne pas.

Voici une extension réécrite qui fonctionne, cela peut aider quelqu'un:

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
la source
2

Une solution vraiment concise utilisant des fonctionnalités ES6 telles que la déstructuration et les retours implicites pour en faire une ligne unique serait:

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

Ou pour simplement obtenir une étiquette, pas une NodeList:

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

Il est en fait beaucoup plus facile d'ajouter un identifiant à l'étiquette dans le formulaire lui-même, par exemple:

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

Ensuite, vous pouvez simplement utiliser quelque chose comme ceci:

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

Le javascript doit être dans une fonction de chargement de corps pour fonctionner.

Juste une pensée, fonctionne à merveille pour moi.

Martie Henry
la source
1

Comme cela a déjà été mentionné, la réponse (actuellement) la mieux notée ne prend pas en compte la possibilité d'intégrer une entrée dans une étiquette.

Puisque personne n'a publié de réponse sans JQuery, voici la mienne:

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

Dans cet exemple, par souci de simplicité, la table de recherche est directement indexée par les éléments HTML d'entrée. Ce n'est guère efficace et vous pouvez l'adapter comme vous le souhaitez.

Vous pouvez utiliser un formulaire comme élément de base ou le document entier si vous souhaitez obtenir des étiquettes pour plusieurs formulaires à la fois.

Aucune vérification n'est effectuée pour un code HTML incorrect (entrées multiples ou manquantes dans les étiquettes, entrée manquante avec l'ID htmlFor correspondant, etc.), mais n'hésitez pas à les ajouter.

Vous souhaiterez peut-être couper les textes de l'étiquette, car des espaces de fin sont souvent présents lorsque l'entrée est incorporée dans l'étiquette.

kuroi neko
la source
1

La meilleure réponse fonctionne parfaitement bien mais dans la plupart des cas, il est excessif et inefficace de parcourir tous les labeléléments.

Voici une fonction efficace pour obtenir le labelqui va avec l' inputélément:

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

Pour moi, cette ligne de code était suffisante:

el = document.getElementById(id).previousElementSibling;

Dans la plupart des cas, le labelsera très proche ou à côté de l'entrée, ce qui signifie que la boucle de la fonction ci-dessus n'a besoin d'itérer qu'un très petit nombre de fois.

Dan Bray
la source
0

avez-vous essayé d'utiliser document.getElementbyID ('id') où id est l'identifiant de l'étiquette ou est la situation où vous ne savez pas laquelle vous recherchez

Josh Mein
la source
Je connais l'identifiant de l'élément d'entrée, mais pas l'identifiant de l'étiquette.
Joel Coehoorn
ne pouvez-vous pas définir un identifiant correspondant pour l'étiquette, tel que input id = 'test' et label id = 'lbl_test "
Josh Mein
0

Utilisez un sélecteur JQuery:

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

Pour les futurs chercheurs ... Ce qui suit est une version jQuery-ified de la réponse acceptée 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]));   
        }
    }
}

En utilisant:

$("#myFormElemId").data("label").css("border","3px solid red");
Type d'objet
la source
+1, mais d'après ce que je vois, il n'y a aucune raison d'utiliser la version jQuery pour le premier bloc: ce n'est ni plus court ni plus lisible, et le javascript simple fonctionnera probablement mieux. Il est cependant agréable d'avoir un exemple jQuery sur la façon de l'utiliser une fois créé.
Joel Coehoorn
De toute évidence, pour beaucoup d'entre nous, il n'y a pas beaucoup de raison technique à cette approche, mais une raison, du moins dans mon cas, est une raison RH. Imaginez que vous ayez une équipe comprenant des concepteurs, des intégrateurs et même des développeurs Jr avec lesquels vous vous êtes habitué à utiliser jQuery. Garder les choses dans le paradigme jQuery peut aider à maintenir la productivité et réduire la frustration.
ObjectType
Ce n'est pas très jQuery-ified . Pourquoi la forboucle terminée each()? Pourquoi la htmlForplace de attr("for")?
alex
Cela dépend de la perspective, je suppose. La consommation était jQuery-ified, pas les internes.
ObjectType
0

Je sais que c'est vieux, mais j'ai eu du mal avec certaines solutions et j'ai reconstitué tout cela. J'ai testé cela sur Windows (Chrome, Firefox et MSIE) et OS X (Chrome et Safari) et je pense que c'est la solution la plus simple. Cela fonctionne avec ces trois styles de fixation d'une étiquette.

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

Utilisation de jQuery:

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

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

Peter Nosko
la source
Cela ne fonctionne pas réellement - il s'agit simplement de renvoyer le texte de l'élément parent, qui se trouve parfois être le texte souhaité.
John Hascall
0

J'ai fait pour mon propre besoin, peut être utile pour quelqu'un: 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
la source
0

Je suis un peu surpris que personne ne suggère d'utiliser la méthode de relation CSS?

dans une feuille de style, vous pouvez référencer une étiquette à partir du sélecteur d'élément:

<style>

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

</style>

si la case à cocher a un identifiant de 'XXX' alors l'étiquette serait trouvée via jQuery par:

$('#XXX + label');

Vous pouvez également appliquer .find ('+ label') pour renvoyer l'étiquette à partir d'un élément de case à cocher jQuery, c'est-à-dire utile en boucle:

$('input[type=checkbox]').each( function(){
   $(this).find('+ label');
});
Gordon Rouse
la source
Oups, je dois noter que cela repose sur l'étiquette venant directement après l'élément.
Gordon Rouse