Znajdź etykietę html powiązaną z danym wejściem

110

Powiedzmy, że mam formularz HTML. Każde wejście / select / textarea będzie miało odpowiednik <label>z foratrybutem ustawionym na id jego towarzysza. W tym przypadku wiem, że każde wejście będzie miało tylko jedną etykietę.

Biorąc pod uwagę element wejściowy w javascript - na przykład poprzez zdarzenie onkeyup - jaki jest najlepszy sposób na znalezienie powiązanej etykiety?

Joel Coehoorn
źródło
5
Zauważ, że element może mieć więcej niż jedną etykietę, widziałem niektóre aplikacje (SAP dla jednej), które mają wiele etykiet na element.
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
lub po prostu node.parentNode.querySelector ("label [for = '" + node.id + "']"). innerHTML; lol
Solomon P Byer

Odpowiedzi:

87

Najpierw zeskanuj stronę w poszukiwaniu etykiet i przypisz odwołanie do etykiety z rzeczywistego elementu formularza:

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

Następnie możesz po prostu przejść:

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

Nie ma potrzeby wyszukiwania tablicy :)

FlySwat
źródło
Czy możesz wyjaśnić, czym różni się korzystanie z właściwości expando od mojego? Nie używam żadnej "tablicy przeglądowej", używam obiektu z właściwościami. Istnieje tylko różnica składniowa między „element.label”, „element ['label']” lub „lookup ['elementId']”. Za kulisami są tym samym .
Tomalak
4
Jest to przyjemniejsze, ponieważ nie muszę trzymać osobnego obiektu wokół - relacja jest przechowywana bezpośrednio z elementem wejściowym.
Joel Coehoorn
3
Powinna się tym
zająć
103

Jeśli używasz jQuery, możesz zrobić coś takiego

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

Jeśli nie używasz jQuery, będziesz musiał wyszukać etykietę. Oto funkcja, która przyjmuje element jako argument i zwraca skojarzoną etykietę

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
źródło
33

W standardzie HTML5 istnieje labelswłaściwość wskazująca na etykiety skojarzone z elementem wejściowym.

Możesz więc użyć czegoś takiego (obsługa labelswłaściwości natywnej, ale z funkcją awaryjną do pobierania etykiet na wypadek, gdyby przeglądarka jej nie obsługiwała) ...

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

Nawet łatwiej, jeśli używasz 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
źródło
4
Nie tylko w Chrome, jest w standardzie HTML5 .
Bergi
1
To powinno być gotowe. Dzięki!
maxhm10
23

Jestem trochę zaskoczony, że nikt nie wie, że wolno ci:

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

Które nie zostaną odebrane przez któregokolwiek z sugerowanych odpowiedzi, ale będzie poprawnie oznaczyć wejście.

Oto kod, który bierze pod uwagę ten przypadek:

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

Stosowanie:

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

Kilka uwag:

  • Kod został napisany dla przejrzystości, a nie wydajności. Mogą być dostępne bardziej wydajne alternatywy.
  • Ten kod obsługuje pobieranie etykiet wielu elementów za jednym razem. Jeśli nie tego chcesz, dostosuj się w razie potrzeby.
  • To nadal nie dotyczy rzeczy, takich jak aria-labelledbyużycie tego (pozostawione jako ćwiczenie czytelnikowi).
  • Używanie wielu etykiet to trudna sprawa, jeśli chodzi o wsparcie w różnych programach użytkownika i technologiach pomocniczych, więc dobrze przetestuj i używaj na własne ryzyko itp.
  • Tak, można to również zaimplementować bez użycia jQuery. :-)
Gijs
źródło
6
Miło widzieć, jak ktoś przywołuje niejawne skojarzenie z etykietą, zamiast zakładać, że element zawsze będzie zawierał foratrybut label.
Josh Habdas
14

Wcześniej...

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

Później...

var myLabel = lookup[myInput.id];

Snarky komentarz: Tak, możesz to również zrobić za pomocą JQuery. :-)

Tomalak
źródło
1
Miły. Zmienię to trochę, tak aby przy pierwszym wywołaniu metody było budowane wyszukiwanie, ale powinno to załatwić sprawę.
Joel Coehoorn
Zasugerowałem, że możesz zbudować wyszukiwanie tylko raz.
Tomalak
Należy pamiętać, że jest w nim mały błąd: użyj właściwości „htmlFor”, a nie „for”, ponieważ to ostatnie jest słowem zastrzeżonym w JS. Zwykle zapominam o tym, używając obiektów etykiet ... :-)
Tomalak
Mam sposób, aby to zrobić bez tablicy wyszukiwania powyżej.
FlySwat
Miałem na myśli przeniesienie kodu init do metody, a nie robienie tego tylko raz :(
Joel Coehoorn,
13

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

To odpowiada na pytanie w najprostszy i najprostszy sposób. Wykorzystuje javascript typu vanilla i działa na wszystkich przeglądarkach głównego strumienia.

Luigi D'Amico
źródło
To nie daje odpowiedzi na pytanie. Gdy zdobędziesz wystarczającą reputację , będziesz mógł komentować każdy post ; zamiast tego udziel odpowiedzi, które nie wymagają wyjaśnień od pytającego . - Z recenzji
loki
1
To z całą pewnością daje odpowiedź na pytanie @loki Tylko dlatego, że nie ma na to dalszych wyjaśnień, nie oznacza to, że jest błędne lub nie próbowano na nie odpowiedzieć.
geisterfurz007
Najprostsza i użyteczna odpowiedź! Dzięki!
iedmrc,
8

z jquery możesz zrobić coś takiego

var nameOfLabel = someInput.attr('id');
var label = $("label[for='" + nameOfLabel + "']");
AndreasKnudsen
źródło
Potencjalnie pomija etykiety, które są przodkami.
Alex
4

Jeśli chcesz użyć querySelector (a możesz nawet do IE9, a czasem IE8!), Inna metoda staje się użyteczna.

Jeśli twoje pole formularza ma identyfikator i używasz foratrybutu etykiety , staje się to całkiem proste w nowoczesnym 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);
});

Niektórzy zauważyli o wielu etykietach; jeśli wszystkie używają tej samej wartości foratrybutu, po prostu użyj querySelectorAllzamiast querySelectori pętla, aby uzyskać wszystko, czego potrzebujesz.

Brendan
źródło
3

Wszystkie inne odpowiedzi są bardzo nieaktualne!

Wszystko co musisz zrobić to:

input.labels

HTML5 jest obsługiwany przez wszystkie główne przeglądarki już od wielu lat. Nie ma absolutnie żadnego powodu, dla którego powinieneś zrobić to od podstaw samodzielnie lub wypełnić go w całości! Dosłownie po prostu użyj input.labelsi rozwiązuje wszystkie twoje problemy.

dj nag
źródło
1
Według tej strony , input.labelsnie jest obsługiwane przez IE lub Firefox Edge, i dopiero dodaje wsparcie.
Antti29,
@ Antti29 Możesz dodać funkcjonalność za pomocą podkładki: github.com/termi/ES5-DOM-SHIM Możesz zobaczyć dodawaną funkcję tutaj: github.com/termi/ES5-DOM-SHIM/blob/…
ADJenks
2
$("label[for='inputId']").text()

Pomogło mi to uzyskać etykietę elementu wejściowego za pomocą jego identyfikatora.

haifacarina
źródło
2

Odpowiedź od Gijsa była dla mnie najcenniejsza, ale niestety rozszerzenie nie działa.

Oto przepisane rozszerzenie, które działa, może komuś pomóc:

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
źródło
2

Naprawdę zwięzłym rozwiązaniem wykorzystującym funkcje ES6, takie jak destrukturyzacja i niejawne zwroty, w celu przekształcenia go w poręczny jeden liniowiec, byłoby:

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

Lub po prostu uzyskać jedną etykietę, a nie NodeList:

const getFirstLabel = ({ labels, id }) => labels && labels[0] || document.querySelector(`label[for=${id}]`)
StateOfTheArtJonas
źródło
1

W rzeczywistości znacznie łatwiej jest dodać identyfikator do etykiety w samym formularzu, na przykład:

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

Następnie możesz po prostu użyć czegoś takiego:

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

Aby kod JavaScript działał, musi znajdować się w funkcji ładowania ciała.

Tylko myśl, działa na mnie pięknie.

Martie Henry
źródło
1

Jak już wspomniano, (obecnie) najwyżej oceniana odpowiedź nie uwzględnia możliwości osadzenia wejścia wewnątrz etykiety.

Ponieważ nikt nie opublikował odpowiedzi wolnej od JQuery, oto moja:

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

W tym przykładzie, dla uproszczenia, tabela przeglądowa jest bezpośrednio indeksowana przez wejściowe elementy HTML. Jest to mało wydajne i możesz je dostosować w dowolny sposób.

Możesz użyć formularza jako elementu podstawowego lub całego dokumentu, jeśli chcesz uzyskać etykiety dla wielu formularzy jednocześnie.

Nie sprawdza się nieprawidłowego kodu HTML (wiele lub brak danych wejściowych w etykietach, brak danych wejściowych z odpowiednim identyfikatorem htmlFor itp.), Ale możesz je dodać.

Możesz chcieć przyciąć teksty etykiety, ponieważ końcowe spacje są często obecne, gdy dane wejściowe są osadzone w etykiecie.

kuroi neko
źródło
1

Najlepsza odpowiedź działa doskonale, ale w większości przypadków pętla przez wszystkie labelelementy jest przesadna i nieefektywna .

Oto skuteczna funkcja, która pozwala uzyskać to, labelco pasuje do inputelementu:

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

Dla mnie wystarczyła ta jedna linijka kodu:

el = document.getElementById(id).previousElementSibling;

W większości przypadków labelbędzie znajdować się bardzo blisko wejścia lub obok niego, co oznacza, że ​​pętla w powyższej funkcji musi wykonać iterację bardzo małą liczbę razy.

Dan Bray
źródło
0

czy próbowałeś użyć document.getElementbyID ('id'), gdzie id jest identyfikatorem etykiety lub jest to sytuacja, w której nie wiesz, której szukasz

Josh Mein
źródło
Znam identyfikator elementu wejściowego, ale nie znam identyfikatora etykiety.
Joel Coehoorn
czy nie możesz ustawić odpowiedniego identyfikatora dla etykiety, np. input id = 'test' i label id = 'lbl_test "
Josh Mein
0

Użyj selektora JQuery:

$("label[for="+inputElement.id+"]")
Mike McKay
źródło
0

Dla przyszłych poszukiwaczy ... Poniżej znajduje się wersja zaakceptowanej odpowiedzi FlySwat wykorzystująca jQuery:

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

Za pomocą:

$("#myFormElemId").data("label").css("border","3px solid red");
Rodzaj obiektu
źródło
+1, ale z tego, co widzę, nie ma powodu, aby używać wersji jQuery w pierwszym bloku: nie jest ona ani krótsza ani bardziej czytelna, a zwykły javascript prawdopodobnie będzie działał lepiej. Jednak fajnie jest mieć przykład jQuery na temat tego, jak go używać po utworzeniu.
Joel Coehoorn
Oczywiście dla wielu z nas nie ma technicznego powodu takiego podejścia, raczej powód, przynajmniej w moim przypadku, to powód HR. Wyobraź sobie, że masz zespół składający się z projektantów, integratorów, a nawet programistów Jr, których zwalniasz, przyzwyczaiłeś się do używania jQuery. Utrzymanie paradygmatu jQuery może pomóc w utrzymaniu produktywności i zmniejszeniu frustracji.
ObjectType
To nie jest bardzo oparte na jQuery . Dlaczego forpętla się skończyła each()? Dlaczego htmlForzamiast attr("for")?
Alex,
Chyba zależy od perspektywy. Konsumpcja była oparta na jQuery, a nie na elementach wewnętrznych.
ObjectType
0

Wiem, że to jest stare, ale miałem problem z niektórymi rozwiązaniami i złożyłem to razem. Przetestowałem to na Windows (Chrome, Firefox i MSIE) i OS X (Chrome i Safari) i uważam, że jest to najprostsze rozwiązanie. Działa z tymi trzema stylami mocowania etykiety.

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

Korzystanie z jQuery:

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

Mój JSFiddle: http://jsfiddle.net/pnosko/6PQCw/

Peter Nosko
źródło
To tak naprawdę nie działa - po prostu zwraca tekst elementu nadrzędnego, który czasami jest tekstem, który chcesz.
John Hascall
0

Zrobiłem na własne potrzeby, może być przydatny dla kogoś: 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
źródło
0

Jestem trochę zaskoczony, że nikt nie sugeruje użycia metody relacji CSS?

w arkuszu stylów możesz odwołać się do etykiety z selektora elementów:

<style>

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

</style>

jeśli pole wyboru ma identyfikator „XXX”, etykietę można znaleźć w jQuery przez:

$('#XXX + label');

Możesz również zastosować .find ('+ label'), aby zwrócić etykietę z elementu jQuery checkbox, np. Przydatne podczas zapętlania:

$('input[type=checkbox]').each( function(){
   $(this).find('+ label');
});
Gordon Rouse
źródło
Ups, powinienem zauważyć, że zależy to od etykiety znajdującej się bezpośrednio po elemencie.
Gordon Rouse