Suchen Sie die HTML-Bezeichnung, die einer bestimmten Eingabe zugeordnet ist

109

Angenommen, ich habe ein HTML-Formular. Jeder Eingang / select / Textfeld wird ein entsprechendes haben <label>mit dem forAttribut auf die ID des Begleiters es. In diesem Fall weiß ich, dass jeder Eingang nur eine einzige Bezeichnung hat.

Was ist bei einem Eingabeelement in Javascript - beispielsweise über ein Onkeyup-Ereignis - der beste Weg, um das zugehörige Label zu finden?

Joel Coehoorn
quelle
5
Beachten Sie, dass ein Element möglicherweise mehr als eine Bezeichnung hat. Ich habe einige Anwendungen (SAP für eine) gesehen, die mehrere Beschriftungen pro Element haben.
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
oder einfach node.parentNode.querySelector ("label [for = '" + node.id + "']"). innerHTML; lol
Solomon P Byer

Antworten:

87

Scannen Sie zunächst die Seite nach Beschriftungen und weisen Sie der Beschriftung aus dem eigentlichen Formularelement einen Verweis zu:

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

Dann können Sie einfach gehen:

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

Keine Notwendigkeit für ein Lookup-Array :)

FlySwat
quelle
Können Sie erklären, wo sich Ihre Verwendung einer expando-Eigenschaft von meiner unterscheidet? Ich verwende kein "Lookup-Array", sondern ein Objekt mit Eigenschaften. Es gibt nur einen syntaktischen Unterschied zwischen "element.label", "element ['label']" oder "lookup ['elementId']". Hinter den Kulissen sind sie dasselbe .
Tomalak
4
Das ist schöner, weil ich kein separates Objekt in der Nähe haben muss - die Beziehung wird direkt mit dem Eingabeelement gespeichert.
Joel Coehoorn
3
Dies sollte vom Browser erledigt werden
andho
103

Wenn Sie jQuery verwenden, können Sie so etwas tun

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

Wenn Sie jQuery nicht verwenden, müssen Sie nach dem Label suchen. Hier ist eine Funktion, die das Element als Argument verwendet und die zugehörige Bezeichnung zurückgibt

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

labelsDer HTML5-Standard enthält eine Eigenschaft, die auf Beschriftungen verweist, die einem Eingabeelement zugeordnet sind.

Sie könnten also so etwas verwenden (Unterstützung für native labelsEigenschaften, aber mit einem Fallback zum Abrufen von Etiketten, falls der Browser dies nicht unterstützt) ...

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

Noch einfacher, wenn Sie jQuery verwenden ...

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
quelle
4
Nicht nur in Chrome, sondern auch im HTML5-Standard .
Bergi
1
Dies sollte waaaay sein. Vielen Dank!
Maxhm10
23

Ich bin ein bisschen überrascht, dass niemand zu wissen scheint, dass Sie das perfekt dürfen :

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

Welche bekommen wird nicht durch eine der vorgeschlagenen Antworten aufhob, sondern wird die Eingabe korrekt beschriftet.

Hier ist ein Code, der diesen Fall berücksichtigt:

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

Verwendung:

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

Einige Notizen:

  • Der Code wurde aus Gründen der Klarheit geschrieben, nicht aus Gründen der Leistung. Möglicherweise sind leistungsfähigere Alternativen verfügbar.
  • Dieser Code unterstützt das gleichzeitige Abrufen der Beschriftungen mehrerer Elemente. Wenn Sie dies nicht möchten, passen Sie es nach Bedarf an.
  • Dies kümmert sich immer noch nicht um Dinge wie, aria-labelledbywenn Sie das verwenden würden (als Übung dem Leser überlassen).
  • Die Verwendung mehrerer Etiketten ist eine schwierige Angelegenheit, wenn es um die Unterstützung verschiedener Benutzeragenten und unterstützender Technologien geht. Testen Sie sie daher gut und verwenden Sie sie auf eigenes Risiko usw. usw.
  • Ja, Sie können dies auch ohne Verwendung von jQuery implementieren. :-)
Gijs
quelle
6
Es ist schön zu sehen, dass jemand eine implizite Label-Assoziation aufruft, anstatt davon auszugehen, dass fordas labelElement immer ein Attribut enthält .
Josh Habdas
14

Vorhin...

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

Später...

var myLabel = lookup[myInput.id];

Snarky-Kommentar: Ja, Sie können dies auch mit JQuery tun. :-)

Tomalak
quelle
1
Nett. Ich werde das nur ein wenig umgestalten, damit es die Suche beim ersten Aufruf der Methode erstellt, aber es sollte den Trick machen.
Joel Coehoorn
Ich habe angedeutet, dass Sie die Suche nur einmal erstellen würden.
Tomalak
Beachten Sie, dass ein kleiner Fehler aufgetreten ist: Verwenden Sie die Eigenschaft "htmlFor", nicht "for", da letzteres ein reserviertes Wort in JS ist. Ich neige dazu, das zu vergessen, wenn ich Etikettenobjekte benutze ... :-)
Tomalak
Ich habe eine Möglichkeit, dies ohne ein Lookup-Array oben zu tun.
FlySwat
Ich wollte den Init-Code innerhalb der Methode verschieben, nicht nur einmal :(
Joel Coehoorn
13

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

Dies beantwortet die Frage auf einfachste und schlankste Weise. Dies verwendet Vanille-Javascript und funktioniert auf allen richtigen Browsern des Mainstreams.

Luigi D'Amico
quelle
Dies gibt keine Antwort auf die Frage. Sobald Sie einen ausreichenden Ruf haben, können Sie jeden Beitrag kommentieren . Geben Sie stattdessen Antworten, die nicht vom Fragesteller geklärt werden müssen . - Von der Überprüfung
loki
1
Dies liefert definitiv eine Antwort auf die Frage @loki. Nur weil es keine weitere Erklärung dafür gibt, heißt das nicht, dass es falsch ist oder nicht versucht hat, sie zu beantworten.
geisterfurz007
Die einfachste und nützlichste Antwort! Vielen Dank!
Iedmrc
8

mit jquery könnte man so etwas machen

var nameOfLabel = someInput.attr('id');
var label = $("label[for='" + nameOfLabel + "']");
AndreasKnudsen
quelle
Vermisst möglicherweise Etiketten, die Vorfahren sind.
alex
4

Wenn Sie bereit sind, querySelector zu verwenden (und dies sogar bis zu IE9 und manchmal bis zu IE8!), Ist eine andere Methode möglich.

Wenn Ihr Formularfeld eine ID hat und Sie das forAttribut der Bezeichnung verwenden , wird dies in modernem JavaScript ziemlich einfach:

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

Einige haben über mehrere Etiketten bemerkt; Wenn alle den gleichen Wert für das forAttribut verwenden, verwenden Sie einfach querySelectorAllanstelle von querySelectorund durchlaufen Sie, um alles zu erhalten, was Sie benötigen.

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

Dies hat mir geholfen, die Bezeichnung eines Eingabeelements anhand seiner ID zu ermitteln.

Haifacarina
quelle
2

Die Antwort von Gijs war für mich am wertvollsten, aber leider funktioniert die Erweiterung nicht.

Hier ist eine umgeschriebene Erweiterung, die funktioniert. Sie kann jemandem helfen:

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

Alle anderen Antworten sind extrem veraltet !!

Alles was du tun musst, ist:

input.labels

HTML5 wird bereits seit vielen Jahren von allen gängigen Browsern unterstützt. Es gibt absolut keinen Grund, dass Sie dies selbst von Grund auf neu machen oder es polyfill machen müssen! Im wahrsten Sinne des Wortes nur verwenden input.labelsund es löst alle Ihre Probleme.

dj nag
quelle
1
Laut dieser Seite wird input.labelses nicht von IE oder Edge unterstützt, und Firefox hat gerade erst die Unterstützung hinzugefügt.
Antti29
@ Antti29 Sie können die Funktionalität mit einem Shim hinzufügen: github.com/termi/ES5-DOM-SHIM Sie können die hinzugefügte Funktion hier sehen: github.com/termi/ES5-DOM-SHIM/blob/…
ADJenks
2

Eine wirklich prägnante Lösung, die ES6-Funktionen wie Destrukturierung und implizite Renditen verwendet, um daraus einen praktischen Einzeiler zu machen, wäre:

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

Oder um einfach ein Label zu erhalten, keine NodeList:

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

Es ist tatsächlich viel einfacher, dem Etikett im Formular selbst eine ID hinzuzufügen, zum Beispiel:

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

Dann können Sie einfach so etwas verwenden:

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

Das Javascript muss sich in einer Body-Onload-Funktion befinden, um funktionieren zu können.

Nur ein Gedanke, funktioniert wunderbar für mich.

Martie Henry
quelle
1

Wie bereits erwähnt, berücksichtigt die (derzeit) am besten bewertete Antwort nicht die Möglichkeit, eine Eingabe in ein Etikett einzubetten.

Da niemand eine JQuery-freie Antwort gepostet hat, ist hier meine:

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

In diesem Beispiel wird die Nachschlagetabelle der Einfachheit halber direkt durch die eingegebenen HTML-Elemente indiziert. Dies ist kaum effizient und Sie können es anpassen, wie Sie möchten.

Sie können ein Formular als Basiselement oder das gesamte Dokument verwenden, wenn Sie Beschriftungen für mehrere Formulare gleichzeitig erhalten möchten.

Es werden keine Überprüfungen auf falsches HTML durchgeführt (mehrere oder fehlende Eingaben in Beschriftungen, fehlende Eingaben mit der entsprechenden HTMLFor-ID usw.), aber Sie können sie gerne hinzufügen.

Möglicherweise möchten Sie die Beschriftungstexte zuschneiden, da häufig nachgestellte Leerzeichen vorhanden sind, wenn die Eingabe in die Beschriftung eingebettet ist.

kuroi neko
quelle
1

Die beste Antwort funktioniert einwandfrei, aber in den meisten Fällen ist es übertrieben und ineffizient, alle labelElemente zu durchlaufen .

Hier ist eine effiziente Funktion, um das zu erhalten label, was zum inputElement gehört:

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

Für mich war diese eine Codezeile ausreichend:

el = document.getElementById(id).previousElementSibling;

In den meisten Fällen befindet sich das labelsehr nahe oder neben dem Eingang, was bedeutet, dass die Schleife in der obigen Funktion nur sehr wenige Male iteriert werden muss.

Dan Bray
quelle
0

Haben Sie versucht, document.getElementbyID ('id') zu verwenden, wobei id die ID des Etiketts ist oder die Situation ist, in der Sie nicht wissen, nach welcher Sie suchen

Josh Mein
quelle
Ich kenne die ID des Eingabeelements, aber nicht die ID des Etiketts.
Joel Coehoorn
Können Sie keine entsprechende ID für das Label festlegen, z. B. Eingabe-ID = 'Test' und Label-ID = 'lbl_test "
Josh Mein
0

Verwenden Sie einen JQuery-Selektor:

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

Für zukünftige Suchende ... Das Folgende ist eine jQuery-ified-Version der von FlySwat akzeptierten Antwort:

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

Verwenden von:

$("#myFormElemId").data("label").css("border","3px solid red");
Objekttyp
quelle
+1, aber meines Erachtens gibt es keinen Grund, die jQuery-Version für den ersten Block zu verwenden: Sie ist nicht kürzer oder besser lesbar, und das einfache Javascript wird wahrscheinlich eine bessere Leistung erbringen. Es ist jedoch schön, ein jQuery-Beispiel zu haben, wie man es verwendet, wenn es einmal erstellt wurde.
Joel Coehoorn
Offensichtlich gibt es für viele von uns keinen technischen Grund für diesen Ansatz, sondern zumindest in meinem Fall einen HR-Grund. Stellen Sie sich vor, Sie haben ein Team, dem Designer, Integratoren und sogar Jr-Entwickler angehören, die sich an die Verwendung von jQuery gewöhnt haben. Wenn Sie die Dinge im jQuery-Paradigma halten, kann dies dazu beitragen, die Produktivität aufrechtzuerhalten und die Frustration zu verringern.
ObjectType
Dies ist nicht sehr jQuery-ified . Warum ist die forSchleife vorbei each()? Warum das htmlForstatt attr("for")?
Alex
Kommt auf die Perspektive an, denke ich. Der Verbrauch war jQuery-ified, nicht die Interna.
ObjectType
0

Ich weiß, dass dies alt ist, aber ich hatte Probleme mit einigen Lösungen und setzte diese zusammen. Ich habe dies unter Windows (Chrome, Firefox und MSIE) und OS X (Chrome und Safari) getestet und glaube, dass dies die einfachste Lösung ist. Es funktioniert mit diesen drei Arten des Anbringens eines Etiketts.

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

Verwenden von jQuery:

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

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

Peter Nosko
quelle
Dies funktioniert nicht wirklich - es wird nur der Text des übergeordneten Elements zurückgegeben, der manchmal der gewünschte Text ist.
John Hascall
0

Ich habe für meine eigenen Bedürfnisse gemacht, kann für jemanden nützlich sein: 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
quelle
0

Ich bin etwas überrascht, dass niemand vorschlägt, die CSS-Beziehungsmethode zu verwenden.

In einem Stylesheet können Sie über die Elementauswahl auf eine Beschriftung verweisen:

<style>

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

</style>

Wenn das Kontrollkästchen die ID 'XXX' hat, wird die Bezeichnung über jQuery gefunden von:

$('#XXX + label');

Sie können auch .find ('+ label') anwenden, um das Label von einem jQuery-Kontrollkästchen zurückzugeben, dh nützlich beim Schleifen:

$('input[type=checkbox]').each( function(){
   $(this).find('+ label');
});
Gordon Rouse
quelle
Hoppla, ich sollte beachten, dass dies davon abhängt, dass das Etikett direkt nach dem Element steht.
Gordon Rouse