jQuery / Selector / :odd - Seleccionar elementos con índices impares

El selector jQuery :odd elige los índices 1, 3, 5, etc., del conjunto seleccionado, contando desde cero. Son el segundo, cuarto y sexto elemento. Esperar la primera fila por la palabra «impar» lleva al resultado contrario. En código nuevo, delimita el conjunto con un selector CSS normal y después aplica .odd().

Significado y cambio a .odd()

La documentación de :odd lo marca como obsoleto desde jQuery 3.4 y recomienda el método .odd(). Añadido en 3.5, no acepta argumentos y crea un nuevo objeto jQuery con los elementos de índices impares del conjunto actual. Obsoleto no significa eliminado: la comparación se ejecutó correctamente en 3.7.1 y 4.0.0.

Sustituye $("#records > tbody > tr:odd") por $("#records > tbody > tr").odd(). Las versiones anteriores a 3.5 no tienen este método; comprueba la compatibilidad de la aplicación y los complementos antes de actualizar.

Expresión Regla de recuento Resultado inicial
:odd o .odd() sobre los tr de tbody Conjunto de filas de datos, desde cero r2, r4
.odd() sobre todos los tr con encabezado El encabezado ocupa el índice cero r1, r3, r5
tbody tr:nth-child(odd) Posición entre hermanos de cada padre, desde uno r1, r3, r5

Ejecutar un ejemplo completo de tabla

Guarda todo el código en UTF-8 como odd-demo.html y ábrelo en un navegador. No necesitas instalar paquetes, pero sí internet para cargar la distribución oficial desde su red de distribución de contenidos, o CDN. El ejemplo usa 4.0.0.

thead contiene una fila de encabezado y tbody cinco de datos. Los identificadores distinguen las filas; los índices dependen del orden actual del documento y del ámbito seleccionado. Los botones cambian esas condiciones.

<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Odd indexes in table rows</title>
  <style>
    body { font: 16px/1.6 sans-serif; margin: 24px; }
    table { border-collapse: collapse; width: 100%; max-width: 600px; }
    th, td { border: 1px solid #ccc; padding: 8px; text-align: left; }
    tr.marked { background: #fff0b3; }
    button { margin: 4px; padding: 8px; }
  </style>
  <script src="https://code.jquery.com/jquery-4.0.0.min.js"></script>
</head>
<body>
  <h1>Odd indexes in table rows</h1>
  <table id="records">
    <thead><tr id="heading"><th>Item</th><th>Amount</th></tr></thead>
    <tbody>
      <tr id="r1" class="eligible"><td>Item 1</td><td>10</td></tr>
      <tr id="r2"><td>Item 2</td><td>20</td></tr>
      <tr id="r3" class="eligible"><td>Item 3</td><td>30</td></tr>
      <tr id="r4" class="eligible"><td>Item 4</td><td>40</td></tr>
      <tr id="r5" class="eligible"><td>Item 5</td><td>50</td></tr>
    </tbody>
  </table>
  <button type="button" id="data">Data rows .odd()</button>
  <button type="button" id="all">Include header .odd()</button>
  <button type="button" id="css">Data :nth-child(odd)</button>
  <button type="button" id="prepend">Prepend one data row</button>
  <button type="button" id="reset">Reset</button>
  <p id="result" aria-live="polite"></p>
  <script>
    $(function () {
      function show($chosen) {
        $("#records tr").removeClass("marked");
        $chosen.addClass("marked");
        const ids = $chosen.map((_, row) => row.id).get().join(", ");
        $("#result").text(`${ids || "none"} | ${$chosen.length}`);
      }
      function dataRows() {
        show($("#records > tbody > tr").odd());
      }
      $("#data").on("click", dataRows);
      $("#all").on("click", () => show($("#records tr").odd()));
      $("#css").on("click", () => show($("#records > tbody > tr:nth-child(odd)")));
      $("#prepend").on("click", function () {
        if (!$("#extra").length) {
          $("#records > tbody").prepend('<tr id="extra"><td>Extra item</td><td>0</td></tr>');
        }
        dataRows();
      });
      $("#reset").on("click", function () {
        $("#extra").remove();
        dataRows();
      });
      dataRows();
    });
  </script>
</body>
</html>

Al abrir, .odd() solo se aplica a los datos. Se resaltan Item 2 e Item 4 y aparece:

r2, r4 | 2

Cambiar el ámbito, insertar y restablecer

  1. Data rows .odd() cuenta solo los tr hijos directos de tbody. Los índices 1 y 3 dan r2, r4 | 2.
  2. Include header .odd() incluye la fila de thead. El encabezado ocupa el índice cero y cambia el resultado a r1, r3, r5 | 3.
  3. Data :nth-child(odd) selecciona las posiciones 1, 3 y 5 dentro de tbody: r1, r3, r5 | 3. Coincidir con el botón anterior no implica usar la misma regla.
  4. Prepend one data row inserta Extra item al principio de tbody y recalcula .odd(). r1 pasa al índice 1: r1, r3, r5 | 3. Comprobar el identificador extra evita duplicados al repetir la pulsación.
  5. Reset elimina únicamente la fila añadida y vuelve a aplicar .odd() a los datos. Conserva las cinco filas y valores originales y restaura r2, r4 | 2.

show elimina todas las clases marked anteriores antes de marcar el resultado nuevo, por lo que el resaltado no se acumula. En tablas reales, limita también el identificador y las relaciones de hijo directo para excluir otras tablas o tablas anidadas.

Comparar con odd de CSS

Justo después de abrir o pulsar Reset, ejecuta este fragmento en la consola de desarrollo. Las primeras dos líneas comparan el selector antiguo y su sustituto; la última usa :nth-child() con reglas CSS.

const ids = $set => $set.map((_, row) => row.id).get().join(", ");
console.log(ids($("#records > tbody > tr:odd")));
console.log(ids($("#records > tbody > tr").odd()));
console.log(ids($("#records > tbody > tr:nth-child(odd)")));
r2, r4
r2, r4
r1, r3, r5

.odd() cuenta todo el conjunto seleccionado de forma continua. :nth-child(odd) reinicia las posiciones para cada padre, incluidos distintos tbody. :nth-child() cuenta todos los hermanos que sean elementos, independientemente de su etiqueta, y exige además que el candidato en esa posición sea tr. Los espacios de texto y los comentarios no son elementos hermanos.

Orden de filtros y filas dinámicas

r1, r3, r4 y r5 tienen eligible. $("#records > tbody > tr.eligible").odd() reúne primero esas cuatro filas y conserva r3 y r5. Aplicar .odd() a las cinco filas antes de .filter(".eligible") deja solo r4 de entre r2 y r4. El orden cambia el conjunto utilizado para calcular los índices.

Un conjunto vacío o de un elemento carece de índice 1; .odd() también queda vacío. Los resultados no se actualizan automáticamente. Una selección de r2 y r4 guardada antes de insertar sigue conteniendo esos elementos después. Consulta otra vez, como dataRows, para reflejar las posiciones actuales.

Si no responde, revisa la petición jQuery en Network, los errores de Console y jQuery.fn.jquery. Si el resultado parece invertido, comprueba la inclusión del encabezado, el ámbito de tbody, el orden de filtros y las filas añadidas. Distingue el número visible del índice desde cero.