En esta entrada, vamos a explicar como consumir una API con la librería Axios y crearemos un filtro personalizado para darle formato a unos valores que obtendremos de la API. En este caso, el filtro pondrá un punto cada tres números, es decir, hará de separador de millares.
Primero de todo tenemos que añadir las librerías JS y CSS necesarias para el ejemplo.
Añadimos estas librerías JS:
1 2 3 4 5 6 |
https://unpkg.com/vue https://unpkg.com/axios/dist/axios.min.js https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js https://cdnjs.cloudflare.com/ajax/libs/jquery-easing/1.4.1/jquery.easing.min.js https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js https://cdnjs.cloudflare.com/ajax/libs/scrollup/2.4.1/jquery.scrollUp.min.js |
Y añadimos el CSS de Bootstrap:
1 |
https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css |
Una vez ya tenemos todas las librerías necesarias, vamos a empezar creando la instancia de Vue.js:
1 2 3 4 5 6 7 |
new Vue({ el: "#app", data: { textSearch: "", countries: [] } }); |
Y el HTML con un input que lo asignamos (v-model) a la propiedad textSearch del objeto data:
1 2 3 4 5 6 7 |
<div class="container"> <div id="app" class="row"> <div class="col-md-8 col-sm-offset-2"> <input id="input-search" type="text" class="form-control" v-model="textSearch" placeholder='Search...'> </div> </div> </div> |
Como ya he dicho en la introducción de la entrada, vamos a hacer un ejemplo de cómo consumir una API con la librería Axios y Vue.js. He estado buscando y he encontrado una API gratis y que no requiere de autenticación que nos permite obtener datos sobre todos los países del mundo. Lo que haremos, será mostrar una lista de todos los países con unos datos sobre ellos.
En el post donde se explica el ciclo de vida de un componente, se menciona que en el hook created era donde normalmente se ponía las peticiones asíncronas que inicializan propiedades del objeto data. Por tanto, como queremos inicializar la propiedad countries con la lista de países extraída de la API, vamos a añadir el hook created y añadir la petición a la API hecha con Axios:
1 2 3 4 5 6 7 8 9 10 11 12 |
... created: function() { var that = this; axios.get('https://restcountries.eu/rest/v2/all') .then(function (response) { that.countries = response.data; }) .catch(function (error) { console.log(error); }); }, ... |
Como vemos, lo que se hace, es hacer una petición GET a la URL indicada, si todo va bien nos retorna un JSON con diferentes datos, nosotros nos quedamos con la propiedad data de este objeto y la asignamos a la propiedad countries del objeto data de Vue.js. Si hay algún error, pasa por el catch y se muestra por consola.
Ahora vamos a mostrar la lista de países y sus datos. He aplicado unos estilos de Bootstrap:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
<div class="container"> <div id="app" class="row"> <div class="col-md-8 col-sm-offset-2"> <input id="input-search" type="text" class="form-control" v-model="textSearch" placeholder='Search...'> <div id="list-countries" v-if="countries && countries.length"> <div class="panel panel-default" v-for="country of countries"> <div class="panel-heading"> <img v-bind:src="country.flag" alt="" width="30px"> <span>{{country.name}}</span> </div> <div class="panel-body"> <div class="row"> <div class="col-md-6">Capital: <strong>{{country.capital}}</strong></div> <div class="col-md-6">Region: <strong>{{country.region}}</strong></div> </div> <div class="row"> <div class="col-md-6">Currency: <strong>{{country.currencies[0].name}} ({{country.currencies[0].symbol}})</strong></div> <div class="col-md-6">Population: <strong >{{country.population}}</strong></div> </div> </div> </div> </div> <div class="text-center" v-else> No results! </div> </div> </div> </div> |
Ahora tenemos la lista de países con sus datos, pero el buscador no funciona.
Para que funcione, tendremos que crear una computed property que lo que hará será filtrar todo el contenido del array por el nombre del país según si contiene el valor de textSearch, es decir, obtendremos un nuevo array con los países que contengan en su nombre el valor de la propiedad textSearch. Vamos a añadirla:
1 2 3 4 5 6 7 8 9 10 |
... computed: { countriesFilter: function() { var textSearch = this.textSearch; return this.countries.filter(function(el) { return el.name.toLowerCase().indexOf(textSearch.toLowerCase()) !== -1; }); } }, ... |
Para aplicarla, substituimos en esta parte de código countries por countriesFilter, que es el nombre de la computed property:
1 2 3 4 |
... <div id="list-countries" v-if="countriesFilter && countriesFilter.length"> <div class="panel panel-default" v-for="country of countriesFilter"> ... |
Ahora ya funciona el buscador:
Si te fijas en el valor population de la lista de los países, normalmente es un número bastante grande, ya que es la población que tiene ese país, y su lectura es bastante difícil cuando es un número muy grande. Vamos a poner en práctica los filtros personalizados para darle un formato y que quede un poco más elegante y se pueda leer mejor.
1 2 3 4 5 |
Vue.filter('format-thousands', function (value) { // https://stackoverflow.com/a/2901298 return value.toString().replace(/\B(?=(\d{3})+(?!\d))/g, "."); }); ... |
Los filtros personalizados se crean con Vue.filter() indicando el nombre del filtro en el primero parámetro (format-thousands) y en el segundo parámetro le pasamos una función con un parámetro (value) que será el valor a darle formato. Dentro de la función, se añade la lógica que queramos con un return del valor transformado, en este caso, se añade un punto cada 3 dígitos. Esta lógica la he sacado de un post de StackOverflow.
Para aplicar el filtro, vamos a esta parte del código y añadimos donde se muestra el número | format-thousands :
1 2 3 |
... <div class="col-md-6">Population: <strong >{{country.population | format-thousands}}</strong></div> ... |
Lo veremos así:
Por último, como es una lista muy larga le he añadido un botón que se muestra cuando superamos un cierto número de píxeles al hacer scroll para poder subir arriba del todo, donde está el buscador. Así también ponemos en práctica otro hook del ciclo de vida de un componente explicado anteriormente. Ahora será el hook mounted que, como se explica en el post, se puede utilizar para inicializar librerías que dependan del DOM, como, por ejemplo, el plugin jQuery que vamos a utilizar.
1 2 3 4 5 |
... mounted: function() { $.scrollUp(); } ... |
See the Pen Vue.js 2 #7 Axios and Filters by vreaxe (@vreaxe) on CodePen.
-
– https://v1.vuejs.org/guide/custom-filter.html
– https://github.com/mzabriskie/axios
Excelente post!
que pasa si tiene mas de 1 currencies?, no serviría indicar sólo una posición del índice
Currency: {{country.currencies[0].name}} ({{country.currencies[0].symbol}})
Hola Alexis!
Tendrías que hacer un bucle v-for de
country.currencies
.Un saludo!