Bienvenidos sean a este post, hoy continuaremos con la manipulacion de elementos DOM.
En el post anterior vimos una perfecta manera de ordenar nuestra lista, siempre y cuando sea texto, pero es un poco lento y si bien no lo notamos en una pagina de verdad con multiples solicitudes ese retardo se ira sumando y se incrementara causando problemas de performance, pero como podemos solucionarlo? la solucion mas aceptable es pre-computar las claves para su comparacion, la idea es hacer la mayoria del trabajo mas pesado en un bucle inicial y almacenar el resultado mediante el metodo data de jQuery, el cual establece o recupera informacion arbitraria asociada con los elementos de la pagina, para ello tomaremos el codigo del post anterior, en caso de no tenerlo les dejo un link para descargarlo:
Lo que debemos hacer es extraer todos los archivos en un solo directorio, una vez realizado vamos a ir al archivo codigo.js, buscaremos el siguiente bloque de codigo:
$headers.on('click', function(ev) {
ev.preventDefault();
var col = $(this).index();
var lin = $tabla1.find('tbody > tr').get();
lin.sort(function(a, b) {
var keyA = $(a).children('td').eq(col).text();
keyA = $.trim(keyA).toUpperCase();
var keyB = $(b).children('td').eq(col).text();
keyB = $.trim(keyB).toUpperCase();
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});
$.each(lin, function(index, row) {
$tabla1.children('tbody').append(row);
});
});
Y lo modificarermos de la siguiente manera:
$headers.on('click', function(ev) {
ev.preventDefault();
var col = $(this).index();
var lin = $tabla1.find('tbody > tr').each(function(){
var clv = $(this).children('td').eq(col).text();
$(this).data('claveOrd',$.trim(clv).toUpperCase());
}).get();
lin.sort(function(a, b) {
var keyA = $(a).data('claveOrd');
var keyB = $(b).data('claveOrd');
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});
$.each(lin, function(index, row) {
$tabla1.children('tbody').append(row);
});
});
En este caso lo que hicimos es una pequeña modificacion sobre como tomar la informacion contenida en nuestra tabla la almacenaremos en un nuevo objeto llamado clv, despues de cada elemento seleccionado usaremos a data donde crearemos una clave para almacenar la informacion anterior en mayusculas, a comparacion del codigo anterior en lugar de hacer esto cada vez que ordenemos al objeto lin porque ahora para crear nuestras variables para comparar usaremos a data nuevamente para que utilice el valor asociado a esa clave, despues el resto del codigo sigue trabajando de la misma forma, si lo prueban seguira funcionando de la misma forma pero mas rapida y eficiente, como pueden ver el metodo data en conjunto con removeData pueden ser herramientas muy utiles y ser muy superiores a las propiedades expando, pasemos a un tema particular.
Este codigo es util para ordenar el titulo y los autores pero vamos a agregar la posibilidad de ordenar al autor por apellido en lugar de nombre, para ello deberemos ir primero al archivo indice.html y tomaremos las siguientes lineas de cada autor:
<td>Jason Hales , Almantas Karpavicius , Mateus Viegas</td>
<td>David Herron</td><td>David Herron</td>
<td>Karl Swedberg, Jonathan Chaffer</td>
<td>Federico Kereki</td>
Y las modificaremos de la siguiente manerra:
<td>Jason <span class="orden-clave">Hales</span>, Almantas Karpavicius , Mateus Viegas</td>
<td>David <span class="orden-clave">Herron</span></td>
<td>Karl <span class="orden-clave">Swedberg</span>, Jonathan Chaffer</td>
<td>Federico <span class="orden-clave">Kereki</span></td>
Simplemente agregamos un span para aplicarle una clase a cada apellido,, las cuales nos serviran para nuestro siguiente paso, este sera ir al archivo codigo.js y buscaremos el siguiente segmento de codigo:
var lin = $tabla1.find('tbody > tr').each(function(){
var clv = $(this).children('td').eq(col).text();
$(this).data('claveOrd',$.trim(clv).toUpperCase());
}).get();
De la siguiente manera:
var lin = $tabla1.find('tbody > tr').each(function(){
var $celda=$(this).children('td').eq(col);
var clv=$celda.find('span.orden-clave').text()+' ';
clv += $.trim($celda.text()).toUpperCase();
$(this).data('claveOrd', clv);
}).get();
El cambio mas importante esta primero en establecer primero un objeto llamado $celda donde seleccionaremos la celda actual del elemento seleccionado, la siguiente sera el objeto clv donde primero buscaremos en la celda si existe el span que agregamos anteriormente y lo agregaremos junto a un espacio en blanco, en caso de no existir no agregara nada, la siguiente linea agrega el texto de la celda en mayuscula pero elimina todos los espacios en blanco antes y despues del texto mediante trim, es decir lo que haciamos antes, cual es la curiosidad que para los casos del apellido del autor lo agregara delante de todo texto por lo tanto lo ordenara por ese dato, en caso de no existir seguira funcionando como antes, y este dato en clv lo pasamos a data, si lo prueban funcionara de la siguiente forma
Como podemos ver en el video ya tenemos una forma de ordenar de forma lexicografica en titulo y autor, y a su vez en autor por apellido pero todavia no nos sirve para los campos restantes, publicado y precio, pero como podemos adaptarlo para estas dos columnas? bueno, no es una tarea facil pero tampoco tan compleja, si van al archivo indice.html veran que los tags th son de la siguiente forma:
<th class="orden-alfa">Titulo</th>
<th class="orden-alfa">Autor</th>
<th class="orden-fecha">Publicado</th>
<th class="orden-numero">Precio</th>
Cada uno tiene una clase asignada donde indicamos el tipo de orden que necesita, para poder implementarlo vamos al archivo codigo.js y tomemos este segmento de codigo:
$headers
.wrapInner('<a href="#"></a>')
.addClass('orden');
Y modifiquemoslo de la siguiente manera:
$headers.each(function() {
var tipoClave=this.className.replace(/^orden-/,'');
$(this).data('tipoClave', tipoClave);
})
.wrapInner('<a href="#"></a>')
.addClass('orden');
Primero usaremos un each para pasar por todos los elementos th, lo primero que haremos sera definir un objeto que representara el tipo de clave, para ello tomaremos la clase asignada mediante el className pero le aplicamos un replace donde a traves de una expresion regular cambiara el «orden-» por nada, por lo tanto solo nos quedara la palabra que sera utilizada para identificar como ordenarlo, esto despues a traves de data lo asignaremos a la clave con el mismo nombre, luego tenemos las mismas instrucciones que antes, nuestro siguiente paso sera agregar el siguiente bloque de codigo despues del anterior pero antes del evento click:
var clavesOrd = {
alfa: function($celda) {
var clv=$celda.find('span.orden-clave').text()+' ';
clv += $.trim($celda.text()).toUpperCase();
return clv;
},
numero: function($celda) {
var num = $celda.text().replace(/^[^\d.]*/, '');
var clv = parseFloat(num);
if (isNaN(clv)) {
clv = 0;
}
return clv;
},
fecha: function($celda) {
var clv = Date.parse('1 ' + $celda.text());
return clv;
}
};
En este caso definiremos un objeto para ordenar nuestras claves, observen que estan divididas en tres:
- alfa
- numero
- fecha
Cada una representa los distintos tipos de datos que debemos ordenar, alfa sera para los tipos de texto o alfanumericos, dado que haremos un orden lexicografico, si lo observen es el tipo de orden que usamos anteriormente pero ahora devolveremos dicho valor, como antes nos sera especialmentte util para ordenar mediante el apellido o estandar dependiendo de nuestra necesidad, es decir que este cubrira el orden de titulo y autor, el siguiente es numero y en este primero tendremos esta linea:
var num = $celda.text().replace(/^[^\d.]*/, '');
En esta basicamente tomaremos el valor de la celda seleccionada y a traves de replace eliminaremos todo contenido que este delante de los valores numericos, en este caso el simbolo de dolar, en la siguiente linea a esta convertiremos este valor a tipo float, numerico, mediante parseFloat y antes de devolverlo usaremos un condicional donde verifica si es un numero en caso de no serlo establece dicho valor como cero, este nos sera util para ordenar los precios y por ultimo tenemos a fecha donde convertiremos en tiempo unix a nuestro valor mediante Date.parse, pero para ello le agregaremos un 1 antes del mes y año de nuestro texto, esto es asi para convertirlo correctamente dado que el metodo necesita un formato como el siguiente:
Date.parse("1 julio 2020");
Como dijimos esto nos devolvera un tiempo unix o timestamp, es decir los segundos transcurridos desde el 1 de septiembre de 1970 hasta la fecha indicada, con esto podremos ordenar correctamente la columna de publicado, ahora si tenemos tres formas de ordenar nuestros datos, pasemos al siguiente tema y para ello tomaremos el bloque donde capturamos el evento click:
$headers.on('click', function(ev) {
ev.preventDefault();
var col = $(this).index();
var lin = $tabla1.find('tbody > tr').each(function(){
var $celda=$(this).children('td').eq(col);
var clv=$celda.find('span.orden-clave').text()+' ';
clv += $.trim($celda.text()).toUpperCase();
$(this).data('claveOrd', clv);
}).get();
lin.sort(function(a, b) {
var keyA = $(a).data('claveOrd');
var keyB = $(b).data('claveOrd');
if (keyA < keyB) return -1;
if (keyA > keyB) return 1;
return 0;
});
$.each(lin, function(index, row) {
$tabla1.children('tbody').append(row);
});
});
Y lo modificaremos de la siguiente manera:
$headers.on('click', function(ev) {
ev.preventDefault();
var $header = $(this),
col = $header.index(),
tipoClave = $header.data('tipoClave'),
direcOrden = 1;
if (!$.isFunction(clavesOrd[tipoClave])) {
rerturn;
}
if ($header.hasClass('orden-asc')) {
direcOrden = -1;
}
var lin = $tabla1.find('tbody > tr').each(function(){
var $celda=$(this).children('td').eq(col);
$(this).data('claveOrd', clavesOrd[tipoClave]($celda));
}).get();
lin.sort(function(a, b) {
var keyA = $(a).data('claveOrd');
var keyB = $(b).data('claveOrd');
if (keyA < keyB) return -direcOrden;
if (keyA > keyB) return direcOrden;
return 0;
});
$headers.removeClass('orden-asc orden-desc');
$header.addClass(direcOrden == 1 ? 'orden-asc' : 'orden-desc');
$.each(lin, function(index, row) {
$tabla1.children('tbody').append(row);
});
});
Parece mas complejo pero no lo es tanto comencemos con la primera parte, aqui definiremos un objeto que contendra el elemento que elegimos con click, el siguiente sera la columna correspondiente, despues seleccionaremos el tipo de clave que usaremos para ordenar; si sera alfa, numero o fecha, y finalmente la direccion de orden, ascendente o descendente, despues tendremos un condicional donde si el tipo de clavesOrd es distinto de function saldra de este bloque, el siguiente condicional sera para verificar si $header tiene la clase orden-asc si es asi establece un nuevo valor para direcOrden, despues seguimos con la definicion del objeto lin muy similar al anterior pero ahora lo que establecia el orden lo mudamos a clavesOrd y en este lo recuperaremos pero al momento de establecer el valor en data, el orden sera similar al anterior pero al momento de usar los condicionales no devolveremos un valor fijo sino el valor de direcOrd pero uno lo negaremos en caso de ser necesario, el resto sigue de la misma forma, y por ultimo agregaremos este nuevo segmento de codigo antes de aplicar las lineas ordenadas al tbody:
$headers.removeClass('orden-asc orden-desc');
$header.addClass(direcOrden == 1 ? 'orden-asc' : 'orden-desc');
En este caso primero removeremos las dos clases orden-asc y orden-desc, despues las aplicaremos dependiendo del valor de direcOrden, y por ultimo tendremos la funcion each donde aplicaremos todos los valores ordenados en lin al tbody para ordenarlas al momento de seleccionarlas, con todo esto comentado veamos como trabaja ahora nuestra pagina
Nota: Las clases orden-asc y orden-desc se encuentran definidas en el archivo estilo.css
Como pueden ver ahora no solo tenemos una pagina que ordena la informacion de forma mas eficiente sino que tambien podemos indicar cuando esta ascendente o descendente, con esto hemos contemplado la forrma de ordenarlo mediante datos HTML, y antes de finalizar les dejo los codigos finales de este post:
En resumen, hoy hemos visto como mejorar el orden de los elementos, esto mediante la posibilidad de poder almacenar la informacion en conjunto con los elementos DOM, hemos mejorado el oden en base al tipo de dato y por ultimo lo hemos mejorado visualmente, espero les haya sido de uttilidad sigueme en tumblr, Twitter o Facebook para recibir una notificacion cada vez que subo un nuevo post en este blog, nos vemos en el proximo post.


Donación
Es para mantenimento del sitio, gracias!
$1.50
