Implementando un Filtro múltiple en Vue, Experiencia
Por aquí quería mostrarte una implementación que considero interesante que es la de filtro no sé tú pero al menos cuando tú me hablas de filtro yo es algo que yo tomaría que es una operación extremadamente sencilla yo en mis cursos he mostrado un poco Cómo hacer filtros pero usualmente es del lado del servidor es decir a la final si pasáramos todo esto al servidor lo que nosotros haríamos es algo como lo siguiente hay otra forma de hacerlo un poco más como quien dice más al estilo Laravel ahorita no recuerdo cual es por eso que no lo he implementado que es empleando una función no sé si era when una cuestión así tengo que averiguar en la cual es una especie de when pero si la misma no existe no está definido el parámetro Entonces no la Define pero también lo puedes hacer así tipo condicional esto es un como quien dice un simulado sería el de que tengo por acá me parece el de desarrollo libre aquí no perdón el filtro que tengo acá la parte de gestión que puedo buscar puedo filtrar por categoría Estos son las publicaciones está posteado lenguaje etcétera y demás Esta es la aplicación de desarrollo aquí en local Entonces qué es lo que yo hago aquí pregunto si el tipo está definido si el post está definido si el lenguaje está definido y simplemente voy componiendo el query que estamos Armando acá que fíjate que llega es directamente hasta la parte de los Books es decir el paginate que es lo que tengo aquí a la final es la última operación que hago esto es una forma de hacerlo siempre yo lo hago así es muy cómodo realmente y a la final es un filtro cuál es el problema con el otro filtro:
$posts = Post::orderBy($this->sortColumn, $this->sortDirection);
if ($this->type) {
$posts->where('type', $this->type);
}
if ($this->posted) {
$posts->where('posted', $this->posted);
}
if ($this->category_id) {
$posts->where('category_id', $this->category_id);
}
$posts = $posts->paginate(20);
Yo tengo acá no no sé si sabes pero esta pantalla es en Vue:
https://academy.desarrollolibre.net/libros
Es decir está realizada en Vue y como a la final yo tengo aquí toda la Data para mí no tiene sentido hacer una petición nuevamente al servidor porque otra vez ya aquí tengo toda la Data entonces puede ser un filtro en local ya que a la final si yo aplico el filtro nunca va a tener más Data de la que yo tengo originalmente creo que eso se entiende bien si yo tengo 20 libros Entonces qué es lo que yo pinto aquí por defecto todo toda el material disponible que yo tengo por defecto a partir de que yo aplique los filtros es a partir de la de la Data que ya tenemos que es mi total por lo tanto la manera más fácil sería hacer otra petición al servidor en la cual en base a los parámetros que le esté pasando empiezo a aplicar los filtros como te mostraba por acá en Laravel Pero curiosamente esto son uno de los desarrollos de que cuando cambiamos un poco lo que es la capa cómo lo vamos a manejar cambia muchísimo la implementación ya que la parte de cliente a mi juicio al menos como yo lo he podido resolver es un poco más complicado de lo que parecería a primera vista y es un poco por lo que comenté hablándote todo esto Entonces como demonios lo haríamos del lado del cliente otra vez esto es una aplicación en View y aquí la reactividad de View nos juega un poquito una mala pasada a mi juicio porque es precisamente por la forma en la cual vamos a manipular los datos ya que aquí lo que hacemos en el servidor es bueno Si no cumple la condición Simplemente no viene pero aquí Sí ya la tenemos entonces si removemos esa Data del book y luego por ejemplo suponte que la persona está buscando aquí que los libros sean gratis Ah perfecto van a aparecer tal tal y pas cual Bueno ahora quiere verlos de pago Pero obviamente cuando coloco aquí gratis ya descartó los libros de pago por lo tanto si lo removemos de array Entonces ya no lo tenemos y cuando le damos aquí a pago ya no aparecería nada Creo que eso se entiende bastante bien y lo mismo con la parte de tecnologías buen aquí tengo un error ahorita lo chequeo esto no lo he subido todavía Aquí lo tengo hasta la parte del precio y el idioma Bueno Este es en cursos qué es lo que puedes ver acá Entonces cuál es el bendito problema.
Un filtro sencillo
Cómo se puede aplicar este filtro Aquí también tenemos algo interesante si es un filtro sencillo antes no sé si te recuerdas o si la chequeaste pero yo por ejemplo el filtro lo tenía para los cursos y solamente Era uno si era gratis o no es decir era un chat era un filtro básicamente una un campo que tenemos que chequear por lo tanto era extremadamente sencillo aquí te muestro:
<book-item v-for="c in onlyBooksFree ? books.filter((c) => c.price == '0.00') : books" :key="c.id"
:book="c"></book-item>
Filtro complejo
Lo que bueno la copia que yo hice desde el de curso podemos ampliar aquí la función de filtrar que es de javascript lo podemos hacer esto es una array obviamente la ra de libros que estoy imprimiendo por acá y por aquí consultaba Bueno aquí era el curso por eso que quedó la c no la B como te digo copié esto preguntaba por el precio si era igual o igual a cero entonces significa que era un recurso gratis y por lo tanto era el que estaba y si no imprimía aquí todos los libros Fíjate que aparte del filtro por aquí tengo un condicional corto en la cual en base a esta propiedad que otra vez se actualizaba mediante un campo que era un chat si bueno est Esto es un radios antes era un chat se presionaba el chat entonces estaba activo y quería ver los cursos gratis por lo tanto esto se activaba esto era true y se aplicaba el siguiente filtro y se está activado significa que los quiere ver todos que es el que se muestra por defecto y es así de simple pero el problema es cuando ya agregamos dos filtros tres filtros cuatro filtros queda algo tan sencillo como esto ya cambia muchísimo la implementación al menos como yo la he podido solucionar seguramente aquí alguien que sepa muchísimo de javascript que no es mi caso Yo soy más que todo del backend Aunque Bueno también me defiendo bastante bien con javascript pudiéramos implementar un doble filtro aquí ya que por ejemplo aquí esto es una condición pudieras preguntar por dos condiciones cuál es el problema Esta condición es cuando empiezas al entrar acá es de tipo, es decir se tiene que cumplir esto que sea gratis Bueno aquí reventó como te digo esta parte está en desarrollo que esto se cumpla y que se cumpla también esta condición Entonces si se cumplen esas condiciones Entonces es que puedes aplicar esto pero aquí otra vez yo estoy siempre preguntando por algo que existe que es el precio en este caso y también solamente estoy aplicando este condicional cuando esto se activo Entonces cómo hago con la segunda con la segunda condición que sería el segundo campo que sería esto es decir aquí tuviéramos que preguntar si input es free está definido que sería por ejemplo el radio que el radio que tenemos acá y aparte esto que es opcional ya que puedes aplicar de muchas formas puedes solamente aplicar que sean gratis o también puedes aplicar que sea un filtro por solamente la tecnología:
<h5 class="mb-0 ml-3">Precio</h5>
<div>
<input class="mr-2" id="all" type="radio" v-model="onlyBooksPayFree" value="all" />
<label for="all" :class="{ 'font-bold': onlyBooksPayFree == 'all' }">Todos</label>
</div>
<div>
<input class="mr-2" id="free" type="radio" v-model="onlyBooksPayFree" value="free" />
<label for="free" :class="{ 'font-bold': onlyBooksPayFree == 'free' }">Gratis</label>
</div>
<div>
<input class="mr-2" id="pay" type="radio" v-model="onlyBooksPayFree" value="pay" />
<label for="pay" :class="{ 'font-bold': onlyBooksPayFree == 'pay' }">Pago</label>
</div>
</div>
data() {
return {
onlyBooksPayFree: "all"
}
}
O también puedes aplicar un filtro que sea tanto por el precio como por la tecnología, entonces ya hacer todo esto en una línea me parece que creo que es imposible al menos a mí no se me ha ocurrido si se te ocurre a ti puedes comentarlo Pero y puedes ver la dificultad de todo esto y es por lo tanto que ya Ya pasé una implementación un poco más elaborada o muchísimo más elaborada que es lo que te voy a mostrar aquí en pantalla Que obviamente est ya sería escalable aquí tengo un montón de funciones tal cual puedes ver y también tengo aquí algunos watch:
watch: {
onlyBooksPayFree() {
this.filterData()
}
},
Ya que el problema que tenemos aquí precisamente con estos es que bueno si podemos disparar ahí Bueno aquí tengo un error que ahorita lo voy a chequear es que si pudiéramos implementar también unchain para cuando cambia pero con el watch también lo pudiéramos. Este es el de Book tal cual puedes ver que sería que te estoy mostrando por acá Bueno El de acá precio idioma ya esto sería otra cosa que lo tengo en otro lado Entonces qué es lo que hacemos por acá en el watch esto otra vez sería only Spanish English que sería este apartado y el de bueno este de idioma y el de precio sería este otro que tenemos acá que sería simplemente en este caso no es un Boolean porque ya ahí no es condición de verdadero y falso sino ya sin radios qué es lo que puedes ver voy a ver si lo encuentro por acá arriba el puede ser free él puede ser al que es todos o él puede ser d Pay Entonces si quiero colocar cualquier otro renglón ahí por ejemplo un un precio de 5 o algo por el estilo lo podría hacer fácilmente.
Entonces primero observo si por ahí tenemos algún cambio Mediante los watch ya sea para los libros gratis o de pago o ya sea para el idioma Y a partir de aquí llamamos esta función llamada filter Data es la que puedes ver en alguna parte por acá si la encuentro aquí está que lo primero que hace es limpiar todos los filtros anteriores y es precisamente para evitar de si haya ya í ya estamos filtrando la Data entonces volverla a filtrar Entonces yo lo que hago es siempre a comenzar desde cero para partir de un listado completamente limpio como si estuviera mostrando todo que es el el enfoque por defecto que tenemos acá eso es lo que hace esta función que se llama Clean filter Data que voy a encontrarla por acá:
cleanFilterData() {
for (let i = 0; i < this.books.length; i++) {
this.books[i].show = true
}
},
Qué es lo que yo hago por acá otra vez aquí el problema que tenemos es que no podemos eliminar los objetos que tenemos no puedo hacer un un Pull para eliminar los objetos que tenemos aquí ya definidos porque si no como te digo si el usuario viene acá y quiere ver gratis ahora quiere verlos de pago entonces ya yo cuando coloque aquí gratis ya elimino los de pago cosa por lo tanto no mostraría nada entonces no puedo eliminarlo pudiera hacer una copia de la raid eso es otra forma pero ya sería un poco más complicada que la solución que yo estoy mostrando por acá qué es lo que yo hago por acá a la final lo que me interesa es determinar cuáles se van a mostrar o cuáles no para eso aquí me invento y digo otra vez me invento una opción llamada show ya que esto no forma parte del modelo de book:
books[i].show
Es el que tengo por acá book model puedes ver que no está es algo local de javascript y es la ventaja que tenemos en javascript que podemos crear así opciones sin problemas entonces el filtro lo que hace es indicar que todo el mundo se muestre tal cual puedes ver es un poco ineficiente se pudiera decir pero todo esto es desde el cliente y tampoco es un listado muy grande entonces tampoco tengo mucho problema buen.
Esto es lo que hace esto ya a partir de aquí empieza a preguntar qué demonios tengo en los filtros ya que otra vez puede que esto esté definido puede que no entonces en los casos en los cuales a mí me interesa filtrar por esto es cuando es de pago o free ya que cuando aparece al significa que el filtro está desactivado Entonces si esta condición se cumple que es cuando vamos a filtrar empiezo aplicar filtros y qué es lo que hago por acá bueno aquí está un poco al inverso vuelvo a iterar otra vez toda la Data Entonces en este caso que es para filtrar por el precio pregunto si esto es mayor a cero si es mayor a cero se debería demostrar que ya es la condición que yo tengo por aquí pero ahorita te digo porque esto está desactivado y si no lo ocultamos entonces y básicamente el idioma es similar a este aquí le paso un idioma por defecto pero aquí pregunto que si el idioma no es el seleccionado Entonces lo coloco en falso es básicamente lo que estoy haciendo Y es así como puedes ver no es tan trivial la solución o al menos a mi juicio entonces te pudieras preguntar por qué demonios comento esto acá Recuerda que cuando yo estoy limpiando los filtros automáticamente yo los limpio todos es decir muestro toda la Data por lo tanto si yo estoy aplicando aquí dos filtros como te comentaba al inicio significa que se tiene que cumplir tanto esta condición como esta otra condición por lo tanto es un entonces si yo aquí yo puedo tener por ejemplo un libro que sea gratis pero que no esté en español por lo tanto si yo cuando coloco aquí que sea
gratis:
filterData() {
this.cleanFilterData()
if (this.onlyBooksPayFree == 'pay') {
this.applyFilterBookPay()
} else if (this.onlyBooksPayFree == 'free') {
this.applyFilterBookFree()
}
***
}
},
applyFilterBookFree() {
for (let i = 0; i < this.books.length; i++) {
if (this.books[i].price == 0) {
// this.books[i].show = true
}
else {
this.books[i].show = false
}
}
},
Entonces por aquí se mostraría esta condición no se cumpliría ya que el libro sería gratis pero el libro es de pago por lo tanto aquí se ocultaría aquí se funcionaría correctamente el filtro vamos con otro ejemplo que el libro es de pago pero está en español Entonces si venimos acá que el primer que se ejecuta sería el de que es este el que tenemos acá para verificar si es de pago o no Entonces como te digo el libro sería de pago por lo tanto aquí se ocultaría Entonces el siguiente filtro que se va a ejecutar sería este que indica que el idioma está en español por lo tanto aunque esté oculto yo no estoy preguntando por la condición anterior y lo mostraría si dejara esta condición aquí habilitada cosa Que obviamente sería un problema ya que ese libro se tiene que ocultar porque se tenía que cumplir ambas condiciones y es por eso que yo comienzo como te comentaba antes limpio toda la Data por lo tanto todos los libros se pueden mostrar inicialmente y a partir de ahí con que al menos uno de las condiciones aquí no se cumpla en base a los filtros que estamos aplicando y automáticamente lo oculta sin importarle al otro filtro que estamos aplicando si ya se ocultó o no se ocultó En otras palabras Recuerda que también esto es secuencial según lo que tenemos acá en la parte de filter Data de esta forma no nos tenemos que preocupar si ya ese libro fue ocultado por otro filtro en particular por lo tanto si fuera en ese caso para evitar que ocurriera lo que te comentaba el libro sería de pago según el filtro que tengo aquí aplicado el libro sería de pago pero el libro estaría en español se mostraría en este filtro si no Este primer condicional y tener que todavía colocar más lógica aquí en los filtros correspondientes simplemente es preferible hacerlo de la siguiente forma que es utilizando aquí el de show ya que de esa forma es decir otra vez preguntándose si ya se aplicó un filtro anteriormente antes de aplicar la evaluación correspondiente no nos serviría un triunfal si no tuviéramos que aplicar otro tipo de condición otro tipo de estructura por ejemplo sería un uno si no se aplicado ningún filtro un dos si ya ha implicado algún filtro y aparte de eso si se está mostrando o no el libro Entonces sería mucho más complicado para eso simplemente se lo realizaría de esta forma entonces Bueno espero que haya más o menos quedado claro el asunto al menos en caso de que quieras implementar un filtro como el que está viendo en pantalla ya tengas ahí alguna idea de cómo implementarla ya que esto es una solución que se me ocurrió a mí estuve algunos días pensando esto y esto fue lo que se me ocurrió como puedes ver no es tan sencilla como parece.
Otra opción
Seguramente pueden existir muchísimas más otra forma es precisamente trabajando con un array copia una ar que tenga todos los libros Y a partir de ahí vas removiendo esto es decir cada vez que en este caso en ese hipotético escenario cuando aplicamos aquí el client filter Data lo que hacemos es en el de book replicar todos los libros que ya tenemos suponte que tenemos aquí uno llamado book que no lo utilizaremos aquí en el template si no sería simplemente para tener la copia de todos los libros Cuando hacemos aquí filter este de book lo llenaríamos con todo lo que tenemos en el c en el plural Y a partir de ahí cada vez que apliquemos un filtro Si no cumple la condición simplemente vamos removiendo ese objeto que no cumple la condición por lo tanto aquí cuando aplicamos otro filtro no nos tenemos que preocupar de trabajar si ese libro se le aplico yo un filtro se ocultó o qué demonios pasó con el libro si se ocultó en el otro filtro o lo que sea si no directamente ya no existiría Por lo tanto ya aplicaría los filtros nuevamente en base al filtro que está aplicando la función en cuestión sé que es un poco lioso pu que no me hayas entendido todo en detalle pero bueno Cualquier cosa ahí lo puedes comentar de igual manera aquí tienes más o menos el código intenta darle el seguimiento La corrida en caso de que te interese algo como esto y Bueno ahí tú básicamente puedes ir comentando Pero lo bueno de este esquema es que obviamente es bastante escalable lo malo es que Bueno realmente es un poco lioso tal cual puedes ver otra vez compara esto ya que uno cuando ve todo en el servidor uno dice no en el servidor siempre es lo más complicado y aquí en el cliente siempre es lo más sencillo Pero puedes ver que hay muchos casos en los cuales no es así y precisamente algo tan tonto como puede ser un filtro que es como esto que uno dice no esto yo lo hago en 5 minutos bueno esos 5 minutos a mí se me convirtieron en 3 días que no se me ocurria como hacer esta solución pues nada esto sería prácticamente todo lo que te quería comentar en este video eh Recuerda que puedes comentar algo si no entendiste algún paso en particular de lo que estaba explicando o directamente si tú implementaras esto de otra forma que tú consideras que sea más eficiente ya que lo mejor para mí era precisamente hacer esto pero como te digo el problema es cuando ya estamos aplicando son dos filtros o más no se me ocurre como diablos lo puedo colocar todo aquí entonces fue a partir de ahí que hice este monstruo que te mostraba hace unos momentos así que pues nada Gracias por ver y nos vemos en otro video
- Andrés Cruz
Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter