Encuentra la etiqueta html asociada con una entrada determinada

110

Digamos que tengo un formulario html. Cada input / select / textarea tendrá una correspondencia <label>con el foratributo establecido en la identificación de su compañero. En este caso, sé que cada entrada solo tendrá una etiqueta.

Dado un elemento de entrada en javascript, a través de un evento onkeyup, por ejemplo, ¿cuál es la mejor manera de encontrar su etiqueta asociada?

Joel Coehoorn
fuente
5
Tenga en cuenta que un elemento puede tener más de una etiqueta, he visto algunas aplicaciones (SAP para una) que tienen varias etiquetas 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
o simplemente node.parentNode.querySelector ("etiqueta [para = '" + node.id + "']"). innerHTML; lol
Solomon P Byer

Respuestas:

87

Primero, escanee la página en busca de etiquetas y asigne una referencia a la etiqueta desde el elemento de formulario real:

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

Entonces, simplemente puede ir:

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

No se necesita una matriz de búsqueda :)

FlySwat
fuente
¿Puede explicar en qué se diferencia el uso que hace de una propiedad expando del mío? No utilizo ninguna "matriz de búsqueda", utilizo un objeto con propiedades. Solo hay una diferencia sintáctica entre "element.label", "element ['label']" o "lookup ['elementId']". Detrás de escena son lo mismo .
Tomalak
4
Esto es mejor porque no tengo que mantener un objeto separado; la relación se almacena directamente con el elemento de entrada.
Joel Coehoorn
3
Esto debe ser manejado por el navegador
andho
103

Si está utilizando jQuery, puede hacer algo como esto

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

Si no está utilizando jQuery, tendrá que buscar la etiqueta. Aquí hay una función que toma el elemento como argumento y devuelve la etiqueta asociada

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

Hay una labelspropiedad en el estándar HTML5 que apunta a las etiquetas que están asociadas a un elemento de entrada.

Entonces, podría usar algo como esto (soporte para labelspropiedad nativa pero con un respaldo para recuperar etiquetas en caso de que el navegador no lo admita) ...

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

Incluso más fácil si estás 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
fuente
4
No solo en Chrome, está en el estándar HTML5 .
Bergi
1
Esto debería estar muy bien. ¡Gracias!
maxhm10
23

Estoy un poco sorprendido de que nadie parezca saber que estás perfectamente autorizado a hacer:

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

Que no obtendrá recogido por ninguna de las respuestas sugeridas, pero va a etiquetar la entrada correctamente.

Aquí hay un código que tiene en cuenta este caso:

$.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();

Algunas notas:

  • El código fue escrito por claridad, no por rendimiento. Es posible que haya disponibles alternativas más eficaces.
  • Este código admite la obtención de etiquetas de varios elementos de una sola vez. Si eso no es lo que desea, adáptese según sea necesario.
  • Esto todavía no se ocupa de cosas como aria-labelledbysi lo usaras (se deja como ejercicio para el lector).
  • El uso de múltiples etiquetas es un asunto complicado cuando se trata de soporte en diferentes agentes de usuario y tecnologías de asistencia, así que pruebe bien y utilícelo bajo su propio riesgo, etc., etc.
  • Sí, también puede implementar esto sin usar jQuery. :-)
Gijs
fuente
6
Es bueno ver que alguien menciona la asociación de etiquetas implícita en lugar de asumir que siempre habrá un foratributo en el labelelemento.
Josh Habdas
14

Más temprano...

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

Luego...

var myLabel = lookup[myInput.id];

Comentario sarcástico: Sí, también puedes hacerlo con JQuery. :-)

Tomalak
fuente
1
Agradable. Lo refactorizaré solo un poco para que construya la búsqueda la primera vez que llame al método, pero debería funcionar.
Joel Coehoorn
Insinué que crearía la búsqueda solo una vez.
Tomalak
Tenga en cuenta que hubo un pequeño error: use la propiedad "htmlFor", no "for", ya que esta última es una palabra reservada en JS. Tiendo a olvidar que cuando uso objetos de etiqueta ... :-)
Tomalak
Tengo una manera de hacer esto sin una matriz de búsqueda arriba.
FlySwat
Me refería a mover el código de inicio dentro del método, no hacerlo solo una vez :(
Joel Coehoorn
13

document.querySelector ("etiqueta [para =" + vHtmlInputElement.id + "]");

Esto responde a la pregunta de la manera más simple y ágil. Esto usa javascript vainilla y funciona en todos los navegadores adecuados de la corriente principal.

Luigi D'Amico
fuente
Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente reputación , podrá comentar en cualquier publicación ; en su lugar, proporcione respuestas que no requieran aclaración por parte de quien pregunta . - De la opinión
loki
1
Esto definitivamente proporciona una respuesta a la pregunta @loki. El hecho de que no haya más explicaciones no significa que esté mal o no haya intentado responderla.
geisterfurz007
¡La respuesta más sencilla y útil! ¡Gracias!
iedmrc
8

con jquery podrías hacer algo como

var nameOfLabel = someInput.attr('id');
var label = $("label[for='" + nameOfLabel + "']");
AndreasKnudsen
fuente
Potencialmente pasa por alto las etiquetas a pesar de que son ancestros.
alex
4

Si está dispuesto a utilizar querySelector (y puede hacerlo, incluso hasta IE9 y, a veces, IE8), otro método se vuelve viable.

Si su campo de formulario tiene una ID y usa el foratributo de la etiqueta , esto se vuelve bastante simple en 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);
});

Algunos han notado sobre múltiples etiquetas; si todos usan el mismo valor para el foratributo, solo use en querySelectorAlllugar de querySelectory recorra para obtener todo lo que necesita.

Brendan
fuente
3

¡Todas las otras respuestas están extremadamente desactualizadas!

Todo lo que tienes que hacer es:

input.labels

HTML5 ha sido compatible con todos los navegadores principales durante muchos años. ¡No hay absolutamente ninguna razón por la que deba hacer esto desde cero por su cuenta o rellenarlo con polietileno! Literalmente, solo use input.labelsy resuelve todos sus problemas.

dj nag
fuente
1
Según esta página , input.labelsno es compatible con IE o Edge, y Firefox acaba de agregar el soporte.
Antti29
@ Antti29 Puede agregar la funcionalidad usando un shim: github.com/termi/ES5-DOM-SHIM Puede ver la función que se agrega aquí: github.com/termi/ES5-DOM-SHIM/blob/…
ADJenks
2
$("label[for='inputId']").text()

Esto me ayudó a obtener la etiqueta de un elemento de entrada usando su ID.

haifacarina
fuente
2

La respuesta de Gijs fue muy valiosa para mí, pero lamentablemente la extensión no funciona.

Aquí hay una extensión reescrita que funciona, puede ayudar a alguien:

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

Una solución realmente concisa que utiliza características de ES6 como desestructuración y retornos implícitos para convertirlo en una línea práctica sería:

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

O simplemente para obtener una etiqueta, no una NodeList:

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

En realidad, es mucho más fácil agregar una identificación a la etiqueta en el formulario en sí, por ejemplo:

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

Entonces, simplemente puede usar algo como esto:

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

El javascript tiene que estar en una función de carga corporal para que funcione.

Solo un pensamiento, funciona maravillosamente para mí.

Martie Henry
fuente
1

Como ya se mencionó, la respuesta (actualmente) mejor calificada no tiene en cuenta la posibilidad de insertar una entrada dentro de una etiqueta.

Como nadie ha publicado una respuesta sin JQuery, aquí está la mía:

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

En este ejemplo, en aras de la simplicidad, los elementos HTML de entrada indexan directamente la tabla de búsqueda. Esto es poco eficiente y puedes adaptarlo como quieras.

Puede utilizar un formulario como elemento base o el documento completo si desea obtener etiquetas para varios formularios a la vez.

No se realizan verificaciones para HTML incorrecto (entradas múltiples o faltantes dentro de las etiquetas, entrada faltante con la identificación htmlFor correspondiente, etc.), pero no dude en agregarlas.

Es posible que desee recortar los textos de la etiqueta, ya que los espacios finales suelen estar presentes cuando la entrada está incrustada en la etiqueta.

kuroi neko
fuente
1

La mejor respuesta funciona perfectamente bien, pero en la mayoría de los casos, es excesivo e ineficiente recorrer todos los labelelementos.

Aquí hay una función eficiente para obtener la labelque va con el 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 mí, esta línea de código fue suficiente:

el = document.getElementById(id).previousElementSibling;

En la mayoría de los casos, labelestará muy cerca o al lado de la entrada, lo que significa que el ciclo en la función anterior solo necesita iterar un número muy pequeño de veces.

Dan Bray
fuente
0

¿Ha intentado usar document.getElementbyID ('id') donde id es el id de la etiqueta o es la situación en la que no sabe cuál está buscando?

Josh Mein
fuente
Conozco la identificación del elemento de entrada, pero no la identificación de la etiqueta.
Joel Coehoorn
¿No se puede establecer una identificación correspondiente para la etiqueta como input id = 'test' y label id = 'lbl_test "
Josh Mein
0

Utilice un selector de JQuery:

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

Para futuros buscadores ... La siguiente es una versión jQuery-ified de la respuesta aceptada 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]));   
        }
    }
}

Utilizando:

$("#myFormElemId").data("label").css("border","3px solid red");
Tipo de objeto
fuente
+1, pero por lo que veo no hay razón para usar la versión de jQuery para el primer bloque: no es más corta ni más legible, y el javascript simple probablemente funcionará mejor. Sin embargo, es bueno tener un ejemplo de jQuery sobre cómo usarlo una vez creado.
Joel Coehoorn
Obviamente, para muchos de nosotros no hay muchas razones técnicas para este enfoque, más bien una razón, al menos en mi caso, es de recursos humanos. Imagine que tiene un equipo que incluye diseñadores, integradores e incluso desarrolladores Jr a los que se ha acostumbrado a usar jQuery. Mantener las cosas en el paradigma de jQuery puede ayudar a mantener la productividad y reducir la frustración.
ObjectType
Esto no es muy jQuery-ified . ¿Por qué se foracabó el bucle each()? ¿Por qué en htmlForlugar de attr("for")?
alex
Depende de la perspectiva, supongo. El consumo fue jQuery-ified, no los internos.
ObjectType
0

Sé que esto es antiguo, pero tuve problemas con algunas soluciones y lo armé. He probado esto en Windows (Chrome, Firefox y MSIE) y OS X (Chrome y Safari) y creo que esta es la solución más simple. Funciona con estos tres estilos de pegar una 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() );
});

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

Peter Nosko
fuente
En realidad, esto no funciona, solo devuelve el texto del elemento principal, que a veces resulta ser el texto que desea.
John Hascall
0

Lo hice para mi propia necesidad, puede ser útil para alguien: 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
fuente
0

Estoy un poco sorprendido de que nadie sugiera usar el método de relación CSS.

en una hoja de estilo, puede hacer referencia a una etiqueta desde el selector de elementos:

<style>

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

</style>

si la casilla de verificación tiene una identificación de 'XXX', entonces la etiqueta se encontrará a través de jQuery por:

$('#XXX + label');

También puede aplicar .find ('+ etiqueta') para devolver la etiqueta de un elemento de casilla de verificación de jQuery, es decir, útil cuando se repite:

$('input[type=checkbox]').each( function(){
   $(this).find('+ label');
});
Gordon Rouse
fuente
Vaya, debo tener en cuenta que esto depende de que la etiqueta venga directamente después del elemento.
Gordon Rouse