Pregunta

Estoy escribiendo un script de usuario que detecta formularios de direcciones de "envío a" diseñados arbitrariamente y analiza su contenido.Para hacer esto, necesito encontrar "filas" del formulario (que pueden ser o no tr elementos) que contienen tanto la etiqueta de la dirección (como "Nombre", "Dirección1", etc.) como el correspondiente input campo para esa etiqueta.Por ejemplo, en el siguiente fragmento:

<div>
<label>MaidenName</label>
<table><tbody>
    <tr>
        <td><label>FirstName</label></td>
        <td><input value = "Bob"></td>
    </tr>
    <tr>
        <td><label>LastName</label></td>
        <td><input value = "Smith"></td>
    </tr>
    <tr>
        <td><label>CompanyName</label></td>
        <td><input value = "Ink Inc"></td>
    </tr>
</tbody></table>
</div>

Me gustaría combinar todos los tr elementos, porque cada uno contiene una etiqueta de "Nombre" y un campo de entrada.Sin embargo, no quisiera igualar el div debido a la etiqueta "MaidenName", porque tiene un alcance más amplio que las coincidencias encontradas para los campos dentro de la tabla.

Mi algoritmo actual para encontrar estas filas (que a menudo son div elementos en lugar de tr unos) es:

  • Encuentre todos los nodos con las etiquetas de "Nombre" apropiadas
  • Trabajando hacia arriba en el DOM para cada nodo hasta encontrar un nodo que sea un antepasado de un campo de entrada
  • Luego elimine los elementos secundarios que atravesé para llegar allí, dejando solo los elementos principales del conjunto.

Traduciendo desde el puerto en el que estoy trabajando, JQuery Javascript se vería así:

// set up my two lists
var labelNodes = getLabelNodes();
var nodesWithAddress = 
    $().find("input[type='text']:visible, select:visible");

var pathToCommonParents = getLabelNodes()
    .parentsUntil(nodesWithAddressChildren.parents()).parent();

// keep the highest-level nodes, so we only have the common paths - 
//not the nodes between it and the labels.
return combinedNodeSet.filter(
    function (index) {return $(this).find(combinedNodeSet).length == 0});

Esto funciona...pero todo ese recorrido y comparación de gastos generales arruina absolutamente mi desempeño (esto puede tomar cinco segundos o más.)

¿Cuál sería una mejor manera de implementar esto?Creo que el siguiente pseudocódigo sería mejor, pero podría estar equivocado y no sé cómo implementarlo:

var filteredSet = $().find(*).hasAnyOf(labelNodes).hasAnyOf(nodesWithAddress);
return filteredSet.hasNoneOf(filteredSet); 
¿Fue útil?

Solución 2

para generalizar la respuesta de micha para que pueda verse de forma independiente de la página (diferentes etiquetas y niveles de anidamiento):

var labelNodes = getLabelNodes();
var returnNodes = $();

var regexAncestors = labelNodes.parent();

while (regexAncestors.length){
    regexAncestors = regexAncestors.not("body");
    var commonParentNodes = regexAncestors.has("input[type='text']:visible, select:visible");
    returnNodes.add(commonParentNodes);
    regexAncestors = regexAncestors.not(commonParentNodes).parent();
}
return returnNodes;

Otros consejos

ACTUALIZAR

Encontré una solución mejor (ver revisiones). Creo que funcionará perfectamente para usted.

function getMySpeacialElements() {
    var aSpeacialElements = [];
    $("label").each(function() {
        var oParent = $(this).parent(),
            oSpeacial = oParent.parent();
        oSpeacial.children("*").each(function() {
            if ($(this).children("input").length) {
                aSpeacialElements.push(oSpeacial[0]);
            }
        });
    });
    return aSpeacialElements;
}

Demo en vivo

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top