Aplicación TopArtistLA con Vuejs y la api de last.fm

En esta ocasión vamos a crear una aplicación, la cual vamos a llamar TopArtistLA y para crearla vamos a utiluzar webpack-simple

Webpack-Simple: Es un template de Vuejs, un package builder. Es decir que vamos a tener varios archivos separados a lo largo del proyecto, organizados en carpetas, ysta herramienta va a unir esos archivos por nosotros y nos va a devolver el archivo necesario para que nuestra Single Page Aplication funcione.

En una Single Page Aplication tenemos un solo archivo .js, un solo archivo .css y vamos a entregar siempre el mismo archivo HTML, este archivo HTML va a requerir estos archivos .js y .css los cuales van a tener toda la lógica y todo el estilo de nuestra app.

Para utilizar el template webpack-simple de vuejs primero que nada tenemos que tener instalado npm y Nodejs en nuestro equipo, en caso de no tener instalado (debemos instalarlo antes de continuar).

Ahora vamos a ir al repositorio de Webpack-simple en GitHub. Y como vemos estos son los requisitos para instalarlo…

En la terminal de comandos, (si estamos en windos usamos la tecla windows + R y tecleamos cmd) vamos a correr los siguientes comandos:

  • npm install -g vue-cli 
    Esto nos va a permitir correr algunas tareas con el comando vue, a su vez va a descargar el cli (la interfaz de comandos de vuejs para la terminal) y ala finalizar la descarga la va a instalar de manera global (-g) dentro de nuestro sistema operativo.
  • cd desktop
    Acá es donde se vaa crear la carpeta del proyecto, en caso de querer crearla en otro directorio nos ubicamos en el.
  • vue init webpack-simple TopArtistLA
    webpack-simple es el template que va a utilizar para crear el proyecto, TopArtistLA es el nombre del proyecto. En este punto debemos indicarle algunos datos como: nombre del proyecto, descripción, autor, etc.
  • Ahora la terminal nos va a indicar como empezar a utilizar el template:
    cd project-name: Nos ubicamos en el directorio del proyeceto.
    npm install: Este comando va a instalar todas las dependencias que tenga nuestro proyecto inicialmente, más adelante vamos a colocar nuevas dependencias.
    npm run dev: dev en el archivo package.json corre una serie de comandos que básicamente indica que se corra el servidor de webpack en modo de desarrollo, que lo abra en el nevegador y tenga las funcionalidades –hot. Esta funcionalidad es particular del template, nosotros podemos modificar el archivo App.vue y automaticamente se refresca el navegador cada vez que guardemos.

Incorporar stylus y pug

Para instalar las dependencia vamos a la consola (estando ubicados en la carpeta del proyecto) y vamos a correr el siguiente comando:

npm install –save-dev pug pug-loader stylus stylus-loader

Para que webpack pueda interpregar los que copiamos en pug y en stylus es necesario instalar pug-loader y stylus-loader.


Archivos .vue

Vue lo que nos permite hacer es escribir ciertos componentes en archivos separados, estos componentes que estan en archivos separados y que llevan extensión .vue tienen ciertas caracteristicas:

  1. Para escribir el HTML tienen el tag <template> </template> y dentro de el va todo el html que queremos que contenga ese componente.
  2. Tenemos un tag <script> </script> separado del tag <template>, este script no está dentro de un <body>, no esta dentro de un HTML, está separado. Vue gracias a webpack va a juntar todo para entregar un solo archivo JS.
  3. Por ultimo tenemos un tag <style> </style> que es donde van a estar todos los estilos de este componente.

Para empezar a escribir codigo pug es necesario indicarle al <template> que va a estar escrito en codigo pug, lo mismo aplica para los estilos, si queremos copiar nuestros estilos con stylus, debemos indicarle a la etiqueta <style> que va a estar escrita con stylus. Y eso lo hacemos de la siguiente manera:
<template lang=”pug”> </template>
<style lang=”stylus”> </style> 

 


Configurar la api de last.fm

Esta api nos sirve para obtener los artistas Top y utilizarlos en nuestra aplicación. Para descargarnos la api, basta con que vayamos a su sitio web acá a mano derecha vamos a encontrar la seccion de Getting Started, vamos a hacer click en Get an API account (en caso de no tener una cuenta, procedemos a crearla… Nos va a solicitar el email contact, descripción del proyecto, callback url (la cual no hace falta que exista).
Luego de llenar el formulario vamos a tener:

  • Nombre de la app
  • API Key
  • Secret
  • Registered To

Vamos a almacenar todos estos datos en nuestra carpeta src del proyecto, para ello vamos a crear un archivo config.js el cual va a ser un modulo de JavaScript y va a exportar un objeto con los datos que vamos a almacenar en el

​export default {
appname: ‘topartistla’,
appKey: ‘8618a50c7509275a0473130c2c5d2c03′,
secret: ‘75d54462f716a518fbb0a3b94709426b’,
registeredTo: ‘david’
}

Ahora vamos a colocar una lista de artistas definida por nosotros mismos, para ello es necesario modificar nuestro componente proncipal (App.vue).
<template lang=”pug”>
#app
img(src=’./assets/logo.png’)
h1 TopArtistLA
ul
li(v-for=”a in artists”) {{ a.name }}
Como podemos ver estamos listando los nombres de los artistas, mezclando un poco de pug y vuejs. Tenemos un ul para mostrar varios items, con un list-items por cada uno de los artistas. El li contiene el atributo v-for el cual se utiliza para hacer cilos de repeticiones, en este caso el li se repite tantas veces como artistas hayan, usando la variable a como iteradora.
Ahora vamos a definir los artistas que vamos a listar, y esto lo vamos a hacer en el apartado <script> de nuestro componente App.vue
<script>
export default {
name: ‘app’,
data () {
return {
 artists: [
{ name: “David Guetta”, value: “david guetta” },
{ name: “Bruno Mars”, value: “bruno mars” },
{ name: “The Beatles”, value: “the beatles” },
{ name: “Martin Garrix”, value: “martin garrix” }
]
}
}
}
</script>
Quedando nuestro código así…
Y en el navegador nos quedaría así…
Como se puede observar definimos un array [ ] de artists, ahora vamos a utilizar la API de last.fm para obtener el top artists
Vamos a ir a last.fm/api 
Vamos a la seccion de Geo –> Geo.getTopArtists
Nos va a dirigir a esta pantalla…
 Como podemos ver en el apartado de Example URLs, podemos utilizar la URL del JSON para obtener el getTopArtists de algún país 
Para ello es necesario pasarle por parametro la appKey que nos proporciono last.fm (la misma que guardamos en el archivo src/config.js), esta api la vamos a settear en la URL, donde dice YOUR_API_KEY y en caso de que querramos filtrar el pais, lo cambiamos donde dice spain
Quedando nuestra URL asi..
Y en el browser lo que vamos a visualizar es un JSON con todos los artistas top del país que le indicamos, en este caso fue ‘venezuela’,
ahora…

¿Como usamos todo el codigo que nos devuelve la api, en nuestra app?

En nuestra carpeta src vamos a crear un archivo llamado index.js el cual va a ser el encargado de hacer los requests a la api…

  1. Vamos a guardar la URL como una const, con comillas invertidas para poder hacer uso de variables dentro de ella sin tener que concatenar :
    const URL = `http://ws.audioscrobbler.com/2.0/?method=geo.gettopartists&country=venezuela&api_key=8618a50c7509275a0473130c2c5d2c03&format=json`
  2. Debido a que la apiKey es un dato fijo, lo vamos a reemplazar por una variable:
    const URL = `http://ws.audioscrobbler.com/2.0/?method=geo.gettopartists&country=venezuela&api_key=${apiKey}&format=json`
  3. Esta apiKey la vamos a obtener de nuestro archivo config.js que es donde está almacenada la info de nuestra app registrada.
    Y para obtenerla vamos a importar el archivo:
    import config from ‘./config.js’
    Para definir la constante:
    const apiKey = config.apiKey        ó tambien         const { apiKey } = config 
    Si la definimos con el segundo parametro, el nombre de la variable debe ir tal cual como se encuentre en el archivo importado, en este caso: config.js
  4. Ahora vamos a hacer el request, y lo vamos a realizar mediante esta función:
    function getArtist () {
    fetch (URL) 
    .then(res => res.json()) 
    .then(json => json.topartists.artist)
    }
    Vamos a utilizar el modulo fetch del browser, utilizando la variable URL que ya definimos anteriormente, le vamos a hacer un fetch a la URL y eso nos va a devolver una promesa.
    Esta promesa vamos a encadenarla con un .then, esta promesa va a recibir una respuesta (res) que es una respuesta del servidor, y lo que queremos hacer es retornar otra promesa… En principio cuando utilizamos fetch nos devuelve un objeto que tiene varios métodos, uno de ellos es JSON (res.json) y este JSON nos devuelve otra promesa la cual va a ir cargando los datos (resultado de la respuesta) a medida que vaya llegando, es decir a través de un string.
    Como se puede ver en el browser, la respuesta del JSON tiene un topartists que es un objeto que tiene el atributo artist y este atributo tiene un array con todos los artistas top del país que le indicamos.
    Y como esto es lo que queremos mostrar, en la segunda promesa vamos a ibtener un JSON y le vamos a pedir json.topartists.artist y eso nos va a devolver el array con todos los artistas.

Para utilizar el modulo index.js que acabamos de crear, vamos a ir a nuestro componente principal (App.vue) y vamos a borrar el contenido estático que tenia el array artist, vamos a dejar el mismo array pero vació [ ].

En este punto debemos tener el código de nuestros archivos, tal cual como esta acá…


Componentes

En esta ocasion vamos a separar en componentes, teniendo un tag para componentes, pero esta vez tendremos nuestro componente en un archivo .vue separado, para ello dentro de la carpeta src vamos a crear una carpeta llamada components y ahi dentro de components, vamos a crear un archivo llamado artista.vue

Y en nuestro archivo App.vue vamos a sustituir el
li(v-for=”a in artists”) {{ a.name }}  por artista(v-for=”a in artists” v-bind:a=”a”)
Como podemos ver es algo similar…
Para la logica de artista vamos a ir al archivo que acabamos de crear (artista.vue) y vamos a proceder a escribir el código correspondiente:
<template lang=”pug”> 
li

h2: a(v-bind:href=”a.url” target=”_blank”) {{ a.name }} 
img (v-bind:src=”a.image[2][‘#text’])

</template> 
<script> 
export default { 
name: ‘artista’,
props: [‘a’]
}
</script>

Ahora debemos importar en nuestro componente principal el componente que acabamos de crear..
<script>
import Artista from ‘./components/Artista.vue’


</script>

Adicionalmente tenemos que indicarle a la vista que uno de los componentes que va a utilizar ese el componente Artista, eso lo hacemos de la siguiente manera:
import getArtist from ‘./api’
import Artista from ‘./components/Artista.vue’
export default {
name: ‘app’,
data () {
return {
artists: []
}
},
components: {
Artista
},
mounted: function(){
const self = this
getArtist()
.then(function(artists){
self.artists = artists
})
}
}


En este punto ya se nos tiene que mostrar en la vista todos los artistas. Pero si vemos el Console del Browser, tenemos un warning el cual nos indica que cada uno de los li del componente artista no está recibiendo una key que lo identifique con respecto al resto.


Nosotros podemos usar la key que queramos, pero vamos a usar el atributo mbid que es el id dentro de lastfm, esto viene en el request que le hacemos a la api.
Esto lo vamos a hacer para poder identificar a los artistas dentro del DOM, porque esto es algo que a vuejs le sirve mucho, ya que al momento de cambiar el orden de los artistas o si quitamos algunos de los elementos, porque cambian los datos. Siempre que utilicemos una repeticion es muy importante que cada uno de los elementos tenga un id, para poder compararlo con el resto de los elementos y poder decidir cual tiene que quitar, cual tiene que agregar, etc.

Entonces vamos a ir a nuestro archivo app.vue y donde tenemos la etiqueta o el tag <artista> le vamos a hacer bind de una nueva propiedad:
v-bind:key=”a.mbid”
Quedando asi:  artista(v-for=”a in artists” v-bind:a=”a” v-bind:key=”a.mbid”)

Y si refrescamos el Browser podemos ver que ya no tenemos el warning que teníamos anteriormente.


Algo que se esta hablando mucho ultimamente es cerca de los moduloso de CSS, en nuestra app, el archivo Artista.vue tenemos estilos para la etiqueta li, h2, img, pero como decia anteriormente webpack compila y une todos los archivos, y nos devuelve un solo archivo .css

Entonces que sicede si en otro componente tambien tenemos una etiqueta li con estilos diferentes? Se sobre-escriben y no se mantiene un orden.
¿Como podemos solucionarlo? Vamos a ir a nuestro archivo Artista.vue y en la etiqueta <style> le vamos a colocar el parametro scope
<style lang=”stylus” scope> …. </style>
Y scope lo que hace es ponerle ciertos id a los elementos, mejor dicho: Le coloca atributos de datos con el fin de evitar pisar el estilo de otros componentes.


Selección de pais

Vamos a permitirle a los usuarios seleccionar el país…
En la documentación de la api  en la seccion de geo.getTopArtists vemos que dentro de los parametros que recibe, uno de ellos es el country como podemos ver es un parametro requerido y tiene cierto estándar ISO3166-1

Ese estándar vemos que hace referencia a un listado de países, con ciertos nombres. Basicamente estos son los paises a los cuales la api presta su función. Sin embargo nosotros solo vamos a usar 4 (Colombia, España, Venezuela y Argentina).

Para ello vamos a ir a la vista en nuestro componente principal y vamos a agregar un combo select, para que el usuario pueda elegir el país.  A su vez debemos hacer un array indicandole el pais y el valor, tal cual como vemos en la imagen…

En este punto tenemos el select en la vista, pero aun no fuciona. Para que funcione vamos a settearle al select el atributo v-model y le vamos a hacer bind a un atributo de la vista que se va a llamar seleccionDePais

select(v-model=”seleccionDePais”)

Y este atributo seleccionDePais debe tener un pais por defecto para cuando se cargue la pag, vamos a declararlo de la siguiente manera:

Ahora vamos a hacer la logica para que cada vez que cambie el seleccionDePais se refresque el listado de artistas.
Para estar esperando o viendo cambios sobre algun atributo, vamos a poner un nuevo atributo en la vista que se llama watch y watch es otro objeto que le vamos a indicar que se fije cuando haya un cambio en seleccionDePais

Como lo que tenemos que hacer cuando haya un cambio es lo mismo que tenemos en el momento o ciclo de vida mounted

mounted: function(){
const self = this
getArtist()
.then(function(artists){
self.artists = artists
})
}

Esto lo vamos a declarar dentro de un metodo que vamos a llamar refrescarArtistas y en el mounted como en el seleccionDePais vamos a llamar a este metodo.

methods: {
refrescarArtistas() {
const self = this
getArtist()
.then(function(artists){
self.artists = artists
})
}
},
mounted() {
this.refrescarArtistas()
},
watch: {
seleccionDePais() {
this.refrescarArtistas()
}
}

Ahora debemos tener en cuenta cual es el valor de seleccionDePais para poder pasarselo al getArtists() y que nos devuelva el top de artistas de ese país.
Entonces cuando llamamos a getArtists le vamos a pasar por parametro el this.seleccionDePais
methods: {
refrescarArtistas(){
const self = this
getArtists(this.seleccionDePais)
.then(function(artists) {
self.artists = artists
})
}
}

Ahora tenemos que modificar el llamado a la api, para que tenga en cuenta esto de seleccionDePais, Eso lo vamos a modificar en el archivo api/index.js

import config from ‘./config’
const { apiKey } = config
const URL = `https://ws.audioscrobbler.com/2.0/?method=geo.gettopartists&country=:pais&api_key=${apiKey}&format=json`

export default function getArtist(pais){
const url = URL.replace(‘:pais’,pais)
return fetch(url)
.then(res => res.json())
.then(json => json.topartists.artist)
}

Primero que nada le pasamos a la funcion getArtists el pais que es el parametro que recibe. En la URL country = venezuela, el cual sustituimos por :pais y antes de hacer el request, hicimos el repace url = URL.replace(‘:pais’,pais) de esta manera donde diga :pais lo vamos a reemplazar por la variable pais que es la que llega de la funcion getArtists(pais) por parametro.
Y por ultimo el request se lo hacemos a la url (minuscula)

Nuestro código debería quedar así:


Spinner CSS

Lo ultimo que vamos a hacer es añadir un Spinner o un Loader css, en este punto podemos seleccionar el top de artistas del pais que queremos, pero no estamos mostrando ningun loader, vamos a hacer un componente aparte, y para eso vamos a usar LoaderCSS 
En la carpeta components vamos a crear un nuevo archivo llamado Spinner.vue
<template>
<div class=”loader”>Loading…</div>
</template>
<script>
export default {
name: ‘Spinner’
}
</script>
<style> /* Acá vamos a colocar el codigo que nos proporciona la app LoaderCSS */ </style>

 

En el archivo App.vue justo antes de ul vamos a settear el spinner que acabamos de crear, y le vamos a pasar el atributo v-show
spinner(v-show=”loading”)
Y este loading tenemos que ponerlo dentro de la data de nuestro componente principal.. loading: true

Al principio va a ser true, pero cada vez que llamemos a la funcion refrescarArtistas() Lo vamos a settear como false

refrescarArtistas() {
const self = this
this.loading = true
document.getElementById(‘ul’).style.display = “none”;
getArtist(self.seleccionDePais)
.then(function(artists){
self.loading = false
document.getElementById(‘ul’).style.display = “inline-block”;
self.artists = artists

})
}
},
components: {
Artista, Spinner
} …

Y por ultimo lo que tenemos que hacer es importarlo: import Spinner from ‘./components/Spinner.vue’

Quedando nuestro código asi: