Bueno, lo primero que vamos a hacer es
instalar Laravel, en este caso yo voy a usar este comando. Este comando de Composer me va a permitir crear un proyecto Laravel nuevo y en vez de "blog" yo voy a poner aquí el nombre de la aplicación, pueden poner el nombre que prefieran, yo voy a ponerle como nombre a este
proyecto "mis pensamientos", lo que en inglés sería "my-thoughts". En este caso no importa si ustedes usan
WampServer, si usan Xampp, si usan Laragon, no importa incluso si usan Apache o Nginx,
pueden tener la configuración que crean conveniente. Lo importante es que puedan crear un proyecto de Laravel nuevo y sobre este vamos a ver cómo trabajar Laravel con Vue. Como siempre, pueden usar el editor de texto de su preferencia, en este caso yo voy a usar Sublime Text, muy bien, una vez que se ha terminado de crear el proyecto aquí en la consola voy a acceder al proyecto, ahora mismo yo voy a configurar rápidamente un VirtualHosts para poder acceder a este proyecto a través de una URL específica y no tener que estar ejecutando este comando a fin de ver el proyecto de forma local.
Le voy a poner el mismo nombre que tiene
el proyecto Laravel, por último como estoy en Windows voy a
modificar también este archivo de hosts le pondré exactamente el mismo nombre que use aquí. Voy a iniciar Apache, en este caso a
través de WampServer y de esta manera es como ya he podido acceder al proyecto de Laravel que acabo de crear sobre este proyecto vamos a trabajar.
Lo primero que vamos a hacer es generar rápidamente un pequeño sistema de autenticación y así mismo vamos a crear una base de datos vacía, en este caso, a esta base de datos le pondré como nombre "pensamientos" y aquí voy a poner mis datos de conexión local, la idea es que creemos una base de datos vacía con la intención de que al ejecutar las migraciones se generen tablas sobre esta base de datos vacía. Entonces vamos a crear una base de datos vacía, esta base de datos tendrá como nombre "thoughts" y sobre esta base de datos vamos a ejecutar nuestras migraciones. Entonces, al actualizar ya tenemos un sistema de autenticación y voy a crear una cuenta rápidamente. Tras registrarme, ya conseguí acceder a la aplicación y vamos a modificar esta vista para hacer uso de Vue justamente en esta ruta llamada home, entonces, dentro de la carpeta de rutas > web vamos a encontrar este contenido, aquí nos dice que la ruta home es
gestionada por HomeController, por lo tanto vamos a ir a HomeController y aquí nosotros vemos que HomeController, a través de su método index está devolviendo una vista llamada home, entonces, si accedemos a resources > views > home.blade.php vamos a encontrarnos con la vista que justamente aquí tenemos antes de integrar Vue, lo primero que vamos a hacer es diseñar aquí, únicamente con HTML, la interfaz que queremos usar.
Entonces, aquí vemos que tenemos un panel, vamos a crear más paneles en la parte inferior y este primer panel lo vamos a usar para ingresar información básicamente, entonces aquí voy a ponerle "¿En que estás
pensando ahora?" dentro de panel-body vamos a poner un formulario, dentro de este formulario vamos a poner un form-group, aquí tendremos un input de tipo text con
clase form-control y vamos a poner aquí una etiqueta que acompañe a esta caja de texto, el name de esta caja de texto será "pensamiento". Entonces lo que haremos a continuación será generar un panel nuevo, por lo tanto, aquí vamos a poner un panel, este panel básicamente va a contener un texto y en la parte superior simplemente dirá "Publicado en" y mostrará la fecha en la que se haya publicado el pensamiento.
Si actualizamos, ya tenemos la interfaz que vamos a usar bueno en realidad nos falta agregar algunos botones, para el formulario, el usuario va a poder
presionar enter sobre la caja de texto o también va a poder hacer uso de un botón, un botón que dirá "Enviar pensamiento", en lo que respecta a cada uno de los pensamientos que ya se registraron vamos a poner aquí un panel-footer y aquí vamos a tener dos botones principalmente, un botón será para editar el pensamiento y otro botón será para eliminarlo.
Si actualizamos, ya estamos viendo, ya estamos viendo esta nueva interfaz. Una vez que hemos pensado en la interfaz que queremos diseñar lo que haremos ahora será empezar a integrar Vue. La idea de usar Vue, es que, cada vez que se envíe un nuevo pensamiento, la página no tenga que refrescarse; cada vez que el usuario quiera editar, no tenga que irse hacia otra vista para editar; cada vez que quiera eliminar, no tenga que esperar a que toda la página entera vuelva a cargar. Vue nos va a permitir actualizar la vista y hacer las peticiones en segundo plano, hacer peticiones en segundo plano, se corresponde con la tecnología Ajax, para hacer estas peticiones HTTP a una API determinada, que en este caso lo vamos a crear también con Laravel, podemos usar distintas bibliotecas, por ejemplo, podemos usar jQuery o podemos usar Axios, en este caso vamos a usar Axios.
Entonces lo primero que haremos
será empezar a usar Vue y por lo tanto tenemos que identificar
qué componentes de Vue vamos a crear, por ejemplo, todos los pensamientos publicados van a ser un componente determinado, el formulario que vamos a tener aquí arriba va a ser otro componente también de Vue y por último, toda esta sección en conjunto se corresponderá también con un componente de Vue. Entonces, ¿qué es lo primero que tenemos que hacer? Lo primero que debemos tener en cuenta es que un proyecto nuevo de Laravel por defecto ya hace uso de Vue.
Aquí tenemos un archivo llamado "app.js" que está dentro de resources > assets > js este archivo, lo que está haciendo básicamente es cargar Vue para que nosotros a partir de aquí lo podamos usar. De hecho Laravel ya ha creado un componente de Vue y lo está cargando el componente que Laravel ha definido se llama ExampleComponent y tiene este contenido.
Además, se está haciendo uso de Vue sobre un elemento llamado "app", este elemento llamado app, es un elemento HTML sobre el cual Vue va a poder funcionar. Esto significa que nosotros aquí en este archivo podemos escribir código de Javascript haciendo uso de características nuevas que presente el lenguaje y no tenemos que preocuparnos por la compatibilidad con navegadores antiguos porque al final todo nuestro código que va a estar aquí va a dar lugar a un archivo llamado app.js que va a estar dentro de la carpeta public aquí por ejemplo vemos este archivo app.js que está dentro de public, cuando una persona visite nuestra página no va a cargar esto de aquí sino que va a cargar el resultado que Webpack va a generar a partir de este archivo de entrada, Aquí en la parte inferior nosotros tenemos un archivo llamado webpack.mix.js Mix es un gestor de recursos que Laravel pone a nuestra disposición y por detrás hace uso de Webpack.
Aquí por ejemplo, estas dos líneas de Mix
hacen lo siguiente: toman este archivo app.js que antes mencionamos, como el archivo de entrada y produce una salida dentro de public > js que es también lo que antes comentábamos Así mismo, hace uso del pre-procesador de css Sass y hace que este archivo que está aquí, dé origen también a un archivo de estilos dentro de la carpeta css. En este caso vamos a ignorar este css y simplemente vamos a hacer uso de lo que aquí se presenta. Ahora la pregunta es, ¿cómo hacemos uso de Mix, cómo hacemos uso de Webpack? Así como nosotros tenemos un gestor de
paquetes para PHP que se llama Composer también existe un gestor de paquetes para,
para Javascript que se llama npm. Entonces, a través de npm vamos a
descargar Laravel Mix; para poder hacer uso de npm, primero tenemos que asegurarnos de tener instalado Node. En este caso yo cuento con esta versión. Si no lo tienen instalado y están en Windows, pueden simplemente ir a la página oficial de Node.
En realidad, la instalación no es nada complicada, si están usando Windows, por ejemplo, basta con que descarguen un archivo ejecutable, presionen siguiente, siguiente y terminen de instalar Node, eso no debería suponer ningún problema para ustedes. Incluso si tienen una versión antigua de Node y quieren actualizarla, los pasos a seguir son exactamente los mismos, no tienen ni siquiera que desinstalar nada, basta con que instalen encima y no habrá
ningún tipo de conflicto. Esta instalación también pondrá a su disposición npm, que es el gestor de paquetes para Javascript y Node y Node.js En este caso, yo ya tengo ambos
instalados por lo que puedo continuar.
Si ustedes no lo tienen instalados, deben instalarlos ahora mismo y continuar entonces viendo este vídeo. ¿Cómo instalamos Laravel Mix? Una alternativa es ejecutar npm install, este comando npm install le dice a npm que descargue todas las dependencias del proyec- todas las dependencias que están listadas en un archivo llamado package.json dentro de este archivo package.json vemos claramente como aquí se encuentra listado laravel-mix entonces, vamos a ejecutar npm install para que todas estas dependencias se terminen instalando, después de unos minutos, cuando termina la descarga, lo que vamos a ver en nuestro proyecto es que se ha creado una carpeta nueva llamada "node_modules" dentro de esta carpeta, es donde se encuentran estos paquetes que se acaban de instalar a través de npm.
Como ya tenemos Laravel Mix, lo que vamos a hacer es ejecutar Laravel Mix para que haga uso de Webpack y para que compile nuestro código Javascript y genere un archivo dentro de public, para ello nosotros ejecutamos npm run watch, con la intención de que Webpack se quede observando posibles cambios que ocurran sobre nuestros archivos y que los compile en ese instante. Esa es la diferencia entre npm run dev, donde la compilación se ejecuta una única vez y npm run watch, que es cuando en este caso Webpack se mantiene escuchando posibles cambios sobre los archivos de entrada. Entonces, volviendo a lo que estábamos, tenemos app.js dentro de assets este archivo lo vamos a modificar, aquí vamos a poner nuestro código Javascript que necesitemos, home.blade.php es nuestra vista, donde vamos a hacer uso de los componentes de Vue, ExampleComponent es un componente de ejemplo que Laravel ha definido en nuestro proyecto, y bueno, entonces lo primero que haremos será incluir este componente dentro de nuestra vista home.
Aquí, nuestra vista home.blade.php es una vista que extiende de un layout más general llamado app, este layout más general, dentro del cuerpo de la página tiene un div con id app, que es justamente sobre el cual se está inicializando nuestra instancia de Vue, esto está haciendo que Vue pueda actuar sobre toda esta sección de nuestra página, o sea que, el contenido que se define aquí dentro de home va a poder modificarse con Vue.
Bien, entonces, ¿qué es lo primero que vamos a hacer? Lo primero que vamos a hacer es renombrar
este componente para representar a cada uno de los
pensamientos que han sido publicados, al hacer esto, como se ha detectado un cambio, Laravel Mix nos acaba de notificar de un error que ha tenido y ese error surge por lo siguiente: que dentro de app.js nosotros estamos diciéndole a Vue que vamos a definir un componente que se encuentra en este archivo, vamos a modificar esto. Nuestro componente se va a llamar de esta manera y el archivo asociado a dicho componente se va a llamar de esta forma, cada vez que hacemos un cambio, Laravel Mix nos está avisando de que se acaba de compilar correctamente y todo lo que estamos modificando, está actualizando este archivo app.js Muy bien, como aquí hemos definido este componente de Vue, esto, nosotros lo podemos usar sobre nuestra vista, por ejemplo, aquí aquí vamos a hacer uso de dicho componente, guardamos, este componente dice "I'm an example component!", soy un componente de ejemplo. Entonces, vamos a actualizar aquí, y como vemos, aquí tenemos debajo nuestro componente de ejemplo, solo que vamos a adecuarlo para que este componente de ejemplo represente esto de aquí.
Los componentes de Vue se representan por un único archivo, tienen extensión ".vue" y dentro de estos componentes, vamos a encontrar principalmente el template asociado al componente y código Javascript que querramos escribir para dicho componente. En nuestro caso, nuestro componente que
representa a un pensamiento publicado, debe tener este contenido, entonces, esto es lo que vamos a poner dentro de nuestro componente, voy a reemplazar esto que está dentro de template por esta nueva estructura que es la que queremos usar, aquí también vamos a guardar. Al actualizar tenemos lo mismo que antes, sólo que esto de aquí ahora es un Vue Component, vamos a crear otro componente para representar lo que tenemos aquí en la parte de arriba. Simplemente voy a crear un archivo nuevo y lo voy a guardar con el nombre FormComponent, entonces, vamos a copiar todo esto,
lo vamos a pegar aquí y nuestro componente que contiene el
formulario es esto de acá.
Entonces, vamos a modificar su template por la estructura que nos interesa, aquí nosotros vemos que tenemos un @if
que hace uso de una variable de sesión, se suele trabajar con esto de aquí cuando
estamos usando Laravel sin Javascript cuando estamos haciendo páginas que
hacen peticiones que refrescan el navegador, en este caso, no vamos a refrescar el navegador, por lo tanto, esto de aquí vamos a tener que mostrar nosotros de otra manera. Aquí, si nosotros ponemos directamente
form-component vamos a obtener un error, el componente no se va a mostrar, eso es porque para poder usarlo tenemos que decirle a Vue de su existencia, entonces aquí, le decimos cómo lo queremos usar y le decimos en qué archivo se define dicho componente.
Actualizamos y volvemos al estado inicial, sólo que ahora estamos usando componentes de Vue. Muy bien, la idea es que con Javascript, nosotros hagamos una petición al servidor en segundo plano para registrar el pensamiento, para editar el pensamiento, para eliminar el pensamiento, eso significa que vamos a desarrollar una pequeña API en Laravel y con Javascript vamos a consumir dicha API y gracias a Vue vamos a poder actualizar nuestra vista.
Pero antes de integrar esto con una API, vamos a escribirlo únicamente usando Javascript, vamos a detectar aquí el evento de envío, vamos a mostrar un nuevo Vue Component y de esta manera una vez que hayamos programado la funcionalidad Frontend pasaremos a implementar la funcionalidad Backend y luego volveremos a la funcionalidad Frontend para que consuman la API que vamos a estar definiendo desde Backend, pero antes de ello vamos a definir
nuestro último componente voy a darle aquí New File y vamos a crear MyThoughtsComponent.vue vamos a copiar uno de ejemplo, vamos a eliminar
lo que está dentro de template y aquí vamos a poner todo esto, ahí está, vamos a registrarlo, tal cual hicimos antes y tras hacer esto, vamos a usar aquí
entonces a ese nuevo componente, guardamos, actualizamos y tenemos lo mismo.
¿Para qué hemos hecho todo esto? Al tener cada componente en un archivo separado vamos a poder trabajar con ellos de una forma más sencilla, por ejemplo, dentro de MyThoughtsComponent, a nosotros nos interesa tener uno de estos por cada objeto Javascript que tengamos o sea que si tenemos tres pensamientos vamos a querer tener este componente tres veces, para ello, nosotros vamos a usar la directiva v-for y aquí vamos a decir que vamos a iterar para cada pensamiento dentro de
un arreglo llamado pensamientos, eso significa que aquí nosotros nosotros vamos a añadir un método más llamado data, este método llamado data va a devolver la data que va a usar este componente, esta data se va a representar a través de un objeto, ¿qué vamos a tener como data?
vamos a tener un arreglo de pensamientos.
Hace un momento acabamos de ver un pequeño error y eso se debe a que aquí nos faltaba una coma. Esto es un objeto, esta es una función, debemos poner una coma antes de la siguiente función. Bien, cuando nosotros usamos esta directiva v-for, es recomendable indicarle a Vue de este modo, cuál va a ser el id de cada uno de los ítems. En este caso vamos a decirle que el identificador de cada pensamiento va a ser su atributo id correspondiente. Entonces, hasta aquí, como nuestro arreglo está vacío, si nosotros actualizamos, no tenemos ningún pensamiento publicado, pero nosotros vamos a poner por ahora, un objeto aquí, a este objeto le vamos a poner id "1" y le vamos a pasar algunos datos más, ¿qué datos va a necesitar cada pensamiento? va a necesitar un texto determinado que es
la descripción, va a necesitar la fecha en que se publicó, entonces aquí vamos a poner description abc y aquí vamos a poner cuando se creó, acabo de guardar los cambios, actualizamos y ahora tenemos un
pensamiento publicado, eso es porque en nuestro arreglo tenemos un objeto, sin embargo la información de este objeto no se está mostrando, porque nuestro componente todavía tiene información constante.
Entonces, dejamos de pensar de forma general y pasamos a pensar de forma particular, ¿qué información tiene un ThoughtComponent?, ¿qué información tiene cada uno de los pensamientos? y pensando en ello, vamos a definir aquí esta función data que va a devolver la información que cada pensamiento va a tener. Entonces, ¿qué data va a tener este componente que representa a un pensamiento? Vamos a tener aquí un objeto llamado pensamiento, este objeto llamado pensamiento, tendrá un id, tendrá una descripción, y asimismo tendrá una fecha de publicación, entonces, estos datos son los que nuestro componente va a usar en su template, publicado en y aquí mostraremos pensamiento.created_at, siguiendo la misma idea, en este párrafo vamos a poner pensamiento.descripción y guardamos. Sin embargo, aquí vemos que no se está mostrando ni la fecha ni la descripción del pensamiento, ello ocurre porque este componente general no está pasando información a este componente más específico, a pesar que aquí tenemos una directiva for, Vue no envía automáticamente esta información al componente, sino que nosotros tenemos que especificar de forma explícita que queremos que dicho
componente haga uso de cada objeto thought.
Para ello, voy a escribir esto y entonces este objeto thought se está enviando a través de una propiedad con el mismo nombre, para que eso lo podamos usar desde este componente más específico, tenemos que añadir aquí un atributo más, llamado props, este tributo props tendrá aquí este valor, de esta manera, cada pensamiento se envía y se enlaza a este componente más específico que recibe esa información desde este componente padre. Si actualizamos, vemos que ahora ya nos funciona la fecha y también nos funciona la descripción del pensamiento. Ahora vamos a hacer que cuando se escriba aquí algo y se presione enter o se presione este botón, se agregue un nuevo elemento a nuestro arreglo de pensamientos, esto significa que dentro del componente queremos que exista una variable thought con este valor y aquí le estamos pasando el objeto thought que tenemos disponible gracias al foro pero aquí nosotros podríamos también enviar como información: un id, una descripción que diga zz y una fecha que diga "111" de esta manera, de tal manera que si actualizamos, tenemos aquí los unos y tenemos aquí las zetas, esto es para demostrar que lo que estoy
poniendo aquí es el objeto thought, esto es lo que queremos enviar y esto es el
valor que queremos usar para dicha variable, entonces continuando, ahora vamos a nuestro FormComponent y aquí tenemos que detectar el evento de submit, o sea ya sea que se presione enter desde aquí o ya sea que se presiona el botón con un clic tenemos que detectar el evento submit sobre el formulario, para ello escribimos "v-on:submit=" y aquí ponemos el método al que queremos llamar, en este caso vamos a llamar a un método "newThought" y entonces procederemos a definir este método.
Para ello, aquí en nuestra sección de script vamos a poner "métodos" y vamos a definir al método newThought y básicamente aquí lo que tenemos que hacer es tomar el texto que ha escrito el usuario, aquí nosotros no tenemos que tomar ninguna fecha ni tomar ningún id porque eso nos lo va a generar el servidor, la API nos va a devolver el id del pensamiento luego de registrarlo y el servidor va a definir también una fecha para dicho pensamiento que estamos registrando. Entonces simplemente nos interesa el
valor que tenga este input para poder leer fácilmente ello, vamos a usar aquí v-model y vamos a ponerle un nombre a esto, vamos a ponerle como nombre descript- si le ponemos como nombre description, entonces aquí, dentro de esta función data vamos a devolver un objeto con la data que queremos usar, en este caso, simplemente vamos a tener una variable llamada description.
Entonces, cuando se llame a este método newThought, nosotros vamos a generar un alerta con el valor de la variable description. Para que de este modo verifiquemos si ya estamos leyendo correctamente la descripción escrita por el usuario y asimismo, si estamos también detectando el evento submit, entonces voy a actualizar aquí la página, voy a escribir "12345", voy a presionar enviar pensamiento, tras hacer ello, vemos que el evento de submit no se está detectando y que más bien se está haciendo una petición GET al servidor, actualizando la página, para prevenir que este evento de submit recargue la página, aquí en vez de submit, debemos usar submit.prevent para que de esta manera usemos esta función y además evitemos el recargo de página que los formularios tienen por defecto.
Entonces, actualizamos, voy a escribir "111222" y presionaré enter, tras hace ello, en la consola vemos un error que dice "description is not defined" eso significa que para que nosotros podamos acceder a esta data, tenemos que usar aquí this, this nos va a permitir el acceso hacia
las variables que tengamos como data. Entonces aquí escribimos "222333", enter y vemos aquí un alert con el valor que hemos ingresado, si yo uso el botón, de igual forma se muestra el alert, eso es porque el evento de submit se llama, ya sea presionando enter o ya sea haciendo clic en este botón, ya tenemos aquí la nueva descripción. Aquí tendríamos que usar la API para registrar el nuevo pensamiento y notificar de este cambio al componente más general que contiene al listado de componentes para que actualice este arreglo. ¿Cómo hacemos ello? ¿Cómo enviamos información desde un
componente hijo hacia un componente padre? Eso lo podemos hacer a través de eventos vamos a definir aquí un evento nuevo, a este evento lo vamos a llamar "new" y vamos a hacer que cuando este evento ocurra nosotros llamamos aquí a esta función "agregar pensamiento", cuando este evento ocurra nosotros vamos a llamar a este método "addThought", por lo tanto vamos a definir ese evento aquí, vamos a poner aquí methods y dentro vamos a definir este nuevo método, este nuevo método se va a llamar a través del evento new que el componente hijo va a generar y aquí vamos a recibir el nuevo pensamiento, de tal manera que haremos this.thoughts.push y sobre el arreglo que tenemos, vamos a poner el nuevo pensamiento.
Entonces, ¿cómo hacemos que
este evento new se genere? eso lo podemos hacer aquí, para generar un evento usamos this.$emit en el primer parámetro decimos cuál es
el evento que queremos generar y en el segundo parámetro ponemos la información que queremos enviar, en este caso vamos a enviar un objeto llamado thought ese objeto llamado thought lo vamos a definir justamente aquí arriba este objeto va a tener un id que lo vamos a obtener del servidor, por ahora le pondremos cualquier valor, tendrá una descripción y tendrá una fecha de registro.
Entonces desde este componente formulario, creamos este objeto, generamos el evento new con esta data, eso lo va a detectar este componente más general, al detectar el evento new llamará a este método addThought que recibirá la data enviada por quien generó el evento, esa data será un objeto o pensamiento que lo vamos a poner sobre nuestro arreglo de pensamientos. Entonces actualizamos y aquí voy a poner un pensamiento que será "q", bueno, aquí nos damos cuenta que no está funcionando adecuadamente lo que queríamos y cada vez que presionamos no obtenemos ningún error en el lado izquierdo, al parecer el evento no se está llamando adecuadamente, antes de continuar, hay que solucionar este problema, aquí nos dice que tenemos una propiedad dentro de data que se llama thought y que actualmente está declarado como prop, en Sublime Text no me detectaba correctamente la sintaxis por eso lo he cerrado y he abierto PhpStorm, de seguro que con algún plugin, Sublime Text reconocería bien la sintaxis, pero para no perder tiempo vamos a continuar aquí, entonces, el warning que hemos estado obteniendo se corresponde con este componente, con ThoughtComponent, el warning nos dice: estás obteniendo thought de forma externa, ya no es necesario que lo definas dentro de data.
Por lo tanto aquí vamos a eliminarlo, porque este objeto va a venir desde el exterior, si actualizamos, vemos que el warning que teníamos ha desaparecido. Veamos ahora porque aquí no está funcionando el evento de submit que antes habíamos definido, nosotros dentro de FormComponent estamos emitiendo un evento llamado new y aquí nosotros estamos escuchando elevento new para que cuando ocurra este evento llamemos al método addThought, el método addThought agrega un pensamiento nuevo a nuestro arreglo de pensamientos. La pregunta es: ¿por qué no está esto funcionando adecuadamente? Lo que ocurre es que el evento se emite desde FormComponent, por lo tanto, este evento debemos ponerlo aquí en vez de acá, que es donde se encontraba, entonces vamos a actualizar y aquí vamos a poner "1122", enviar pensamiento y una vez que hicimos esto, vemos como en la parte inferior aparece un nuevo pensamiento, voy a poner aquí "q", voy a presionar enter y en la parte inferior aparece el pensamiento.
Por ahora estamos poniéndole la misma fecha, porque todavía no está conectado al servidor, vamos a terminar de programar todos los Frontend para luego pasar a programar el Backend con Laravel, una vez que se presiona enviar pensamiento o se presiona enter, este texto tiene que limpiarse. Entonces dentro de FormComponent nosotros vamos a hacer lo siguiente: this.description va a ser igual a una cadena vacía, actualizamos esta variable y como esta
variable está enlazada con el input con esto se estará eliminando su contenido, actualicemos y hagamos una prueba.
Se publica el pensamiento nuevo, y en la parte de arriba el cuadro de texto se encuentra nuevamente vacío, entonces, hemos visto cómo pasar información desde un componente padre a un componente hijo y hemos visto cómo a través de eventos podemos pasar información también desde un componente hijo hacia un componente padre. Ahora, siguiendo la idea de los eventos vamos a implementar la eliminación de pensamientos, aquí, dentro del componente de pensamiento, al botón le vamos a asociar un evento vamos a ponerle aquí v-on:click cuando se haga clic sobre este botón llamaremos al método onClickDelete y entonces vamos a definir dicho método, añadimos un atributo methods y aquí vamos a crear esta función onClickDelete, de esta manera, cuando se haga clic sobre el botón de eliminar, nosotros vamos a producir un evento this.$emit el evento que queremos producir se llamará delete y simplemente vamos a producir este evento llamado delete que lo recibirá este componente padre, ahora sí, de este lado vamos a detectar el evento delete, cuando este evento ocurra nosotros vamos a llamar a una función deleteThought y le vamos a pasar la posición que el pensamiento tiene en el arreglo de pensamientos, para hacer ello, vamos a pasarle index, de tal modo que para acceder a este índice nosotros usaremos aquí unos paréntesis y pondremos aquí index, entonces, de este arreglo de pensamientos accedemos al objeto pensamiento, pero accedemos también al índice que tiene cada pensamiento en el arreglo, ese índice le pasamos a este método deleteThought y vamos ahora a crear dicho método, este método recibe su posición y
nosotros vamos a el arreglo de pensamientos, aquí nosotros podemos llamar desde el arreglo la función splice para que desde esta posición se elimine un elemento.
Entonces, si nosotros actualizamos aquí nuestra página, vamos a añadir unos cuantos elementos y ahora procederemos a eliminarlos, por ejemplo, eliminaremos este que está al medio, eliminaremos este abc y por último este 333. ¡Ya lo tenemos! Lo que nos falta ahora es el editar, entonces, en nuestro componente que representa a un pensamiento, tenemos que detectar el evento de clic sobre el botón de editar y asociarle un método, por ejemplo podemos definir un método onClickEdit, entonces aquí tendremos dicho método, cuando se haga clic sobre onClickEdit, nosotros vamos a cambiar este párrafo por un input, para que podamos hacer ello vamos a necesitar una variable más, una variable que le diga a nuestro componente en qué estado se encuentra, se encuentra en estado de sólo lectura o se encuentra en estado de edición, vamos a añadir aquí dentro de data un valor booleano que determine si el componente se está editando o no, vamos a llamar a este valor booleano editMode.
¿Está en modo edición o no? Por defecto diríamos que no, pero cuando se haga clic en el botón de editar, haremos que editMode sea verdadero. Entonces, dentro de nuestro template, en base al valor de editMode, nosotros vamos a decidir si mostrar un párrafo o mostrar un input, entonces, aquí tendremos el párrafo y aquí tendremos un input de tipo text con clase form-control, diremos entonces, si estamos en modo
edición se verá el párrafo, en caso de que no, se verá el input. Verifiquemos el funcionamiento de estas directivas, actualizamos y aquí vemos que se nos muestra un input en vez de un párrafo, lo que pasa aquí es que el orden debería ser al contrario. si estamos en modo edición mostraremos
el input, si no mostraremos el párrafo y esto, lo vamos a aplicar también para el
botón que tenemos debajo, a lo que me refiero es lo siguiente: vamos a tener un botón que diga guardar guardar cambios, de tal modo que si actualmente se está editando, mostraremos guardar cambios, en caso de que no, mostraremos el botón de editar, ¿y el de eliminar? pues siempre se verá, actualizamos, editMode es falso por defecto, cuando presiono editar, esto cambia, ¿sí? voy a añadir uno nuevo, por defecto editMode es falso, le doy
editar, y esto cambia, puedo eliminar de todas maneras, la idea es que cuando se presione editar, este input muestre la descripción del pensamiento, entonces a este input lo vamos a vincular con la descripción del pensamiento, en nuestro caso, esto está siendo interpretado por Vue y no se trata de directivas de blade, vamos a actualizar, le doy editar, y aquí me dice "abc", voy a crear un nuevo pensamiento, le doy editar, y aquí me dice "123".
¿Ven lo sencillo que es enlazar los
datos con los componentes visuales? Ese es un motivo por el cual se suele usar
Vue en vez de jQuery. Ahora bien, cuando se presione guardar cambios, la idea es que estos cambios se notifiquen al componente padre para que actualice la información del pensamiento correspondiente, para que actualice la información del pensamiento que ha sido modificado, entonces a este guardar cambios le vamos a poner un evento de "click" que llame a onClickUpdate y dentro de métodos vamos a definir onClickUpdate este onClickUpdate lo primero que hará es finalizar con el modo de edición y lo siguiente que hará será emitir un evento, vamos a emitir un evento llamado update y le vamos a pasar como información el pensamiento que acaba de editarse.
Entonces, dentro de MyThoughtsComponent vamos a tener un evento más, no solamente el evento de delete, vamos a tener también un evento update, este evento update va a llamar a updateThought y le vamos a pasar el índice del elemento que ha sido modificado, vamos a copiar rápidamente esta función de aquí y le vamos a cambiar el nombre, entonces, aquí, nosotros vamos a acceder al elemento que está en esta posición y tenemos que actualizarlo con el nuevo valor. ¿Sí?, ¿cómo hacemos esto? Aquí nosotros estamos emitiendo el
evento update con el objeto actualizado, de este lado se captura dicho evento y
se llama a updateThought, entonces aquí lo vamos a pasar como argumentos el índice y los argumentos que vienen originalmente desde la emisión del evento.
Entonces aquí vamos a poder acceder al
pensamiento que ha sido editado, actualizamos, le doy a editar, le pongo 123, le doy guardar cambios y esto se acaba de editar correctamente. El componente hijo lanzó el evento update, el componente padre actualizó el elemento en el arreglo tal como correspondía, voy a añadir un pensamiento nuevo y voy a editarlo y voy a editarlo de esta manera, perfecto, tenemos edición, eliminación y registro, tenemos un CRUD con Vue, pero este no es un CRUD de Vue con Laravel, vamos a crear una pequeña API con Laravel para que esto funcione correctamente, porque así como está solamente tenemos Vue Vue es Frontend. Si yo actualizo, se pierde toda la data. Bien, según comentamos antes ahora vamos a proceder a definir rutas para definir una API que nos permita registrar nuevos pensamientos, editarlos o incluso eliminarlos para que cuando nuestra página se actualice completamente, los cambios que se hayan hecho persistan.
En este caso vamos a crear una API para que sea usada por nuestra propia aplicación, entonces, no vamos a definir un sistema de autenticación para terceros que vayan a usar nuestra API, solamente lo usaremos de forma interna, por lo tanto las rutas las vamos a definir aquí en web.php porque lo que estamos haciendo no es
una SPA completa es más bien un híbrido, donde tenemos múltiples páginas pero estamos aplicando Vue a una página en específico.
Desarrollar una SPA completa implica tener rutas que se manejen también en el lado del cliente e inclusive podría implicar también algunas técnicas como Server Side Rendering, es decir conseguir que el servidor genere la estructura de Vue y devuelva la vista ya lista para que no se tengan que hacer peticiones en el lado del cliente cuando la página carga por primera vez. Entonces según la documentación de Laravel, nosotros podemos definir rutas para recursos y podemos seleccionar qué rutas nos interesan usando only o usando except, otra manera es definir recursos de tipo API en donde ya por defecto Laravel va a omitir create y edit, entonces vamos a copiar esto, de tal manera que vamos a definir un recurso llamado pensamientos y vamos a tener un controlador llamado controlador de pensamientos y vamos a usar este comando de Laravel para definir un controlador que tenga unos métodos asociados a estas rutas que estamos definiendo, entonces aquí, en la terminal, vamos a definir un controlador llamado ThoughtController, le damos enter bueno, lamentablemente aquí, yo no tengo disponible esta opción porque la versión que estoy usando es 5.5.40 no es 5.6 este comando está disponible en 5.6 pero no hay problema, vamos a crear el controlador y vamos a añadirle nosotros los métodos, o más bien dicho, dentro de la versión
5.5 sí que tenemos acceso a este flag vamos a dejar todos los métodos, menos create y edit porque esos no se necesitan, index va a devolver el listado de pensamientos, store va a registrar un nuevo pensamiento, en este caso no necesitamos show porque no vamos a mostrar detalles más específicos cuando se haga clic en uno de ellos, en este caso sí vamos a requerir de update para editar y destroy para eliminar, entonces, en index nosotros simplemente debemos devo- devolver el listado de pensamientos del usuario que ha iniciado sesión.
Para lograr esto, primero que todo vamos a definir nuestra tabla para guardar los pensamientos, para ello usaremos php artistan make:model, vamos a crear este modelo y de paso vamos a crear también su migración correspondiente, entonces aquí vamos a definir las
columnas que va a tener esta tabla, cada pensamiento va a tener una descripción, el id se encuentra aquí, la fecha de registro estará acá, de hecho aquí también estará la fecha de actualización, la última fecha de actualización. Esto de los timestamps ya lo gestiona Laravel internamente, y por último, como es una API, para que sea usada de
forma interna podemos también añadir aquí podemos añadir aquí una clave foránea con la intención de identificar a qué usuario le pertenece cada uno de los pensamientos y que según el usuario que inicie sesión veamos lo que cada uno ha escrito para que cada uno pueda tener su propia bitácora de pensamientos.
Entonces para que este controlador funcione adecuadamente nosotros vamos a exigir que haya un usuario autenticado, en index nosotros vamos a devolver todos los pensamientos asociados con el usuario que haya iniciado sesión, aquí podríamos definir las relaciones entre este modelo y el modelo User, pero vamos ahorrando algo de tiempo, aquí en store vamos a crear un nuevo Thought, le vamos a asignar como descripción la descripción que se envía como parte del request vamos a asociar este pensamiento con el usuario que está autenticado y por último usaremos save, para lo que es el update el user_id no se actualiza, aquí buscamos el pensamiento que tiene el id indicado, modificamos su descripción y guardamos.
Para lo que es la eliminación, buscamos el pensamiento indicado y lo eliminamos, entonces aquí, nosotros vamos a escribir route:list para ver cuáles son las rutas que tenemos actualmente definidas en nuestro archivo de rutas, en la parte final vemos las rutas asociadas con los pensamientos, podemos hacer una petición GET
para atraer todos ellos, una petición POST para registrar uno nuevo, podemos hacer una petición PUT o PATCH para actualizar uno de ellos y podemos hacer una petición DELETE para eliminar uno de ellos.
Aunque hemos creado una migración
nueva, todavía no hemos ejecutado esta migración debemos hacerlo para dar origen a aquí, este-, esta columna entera tiene que
ser también unsigned sin signo, para que coincida con el id que tienen los usuarios, como es probable que haya quedado aquí esto en un estado inconsistente vamos a conectarnos a mysql y vamos a eliminar la base de datos que se llama pensamientos para crearla nuevamente. Y ahora sí ejecutamos las migraciones, ya está, bueno, yo quiero que siempre tengamos un usuario activo, a pesar que hagamos refresh continuamente, por lo tanto voy a crear rápidamente aquí un Seeder, vamos a llamar a este Seeder y lo único que haremos aquí es registrar un usuario para que siempre tengamos uno disponible. Entonces aquí ejecutamos dicho Seeder y ya estamos aquí en nuestra aplicación nuevamente tenemos que conectarla con
las rutas que hemos definido, de tal manera que los cambios que hagamos persistan en la base de datos, vayamos primero con el registro y el listado de pensamientos- el registro ocurre aquí en en FormComponent, aquí en este método new newThought solicitar al servidor que registre un nuevo pensamiento, entonces aquí usaremos axios.post, haremos la petición hacia esta ruta, le pasaremos parámetros y una vez que hayamos recibido una respuesta, vamos a mostrar por consola dicha respuesta.
Entonces, ¿qué parámetros vamos a usar? En este caso nuestra lista de parámetros estará compuesta únicamente por una descripción, veamos si esta petición hasta aquí
funciona correctamente y también en nuestro controlador, una vez que se ha registrado el nuevo pensamiento vamos a devolverlo para que su información esté disponible y podamos entonces acceder a la fecha y
al id correspondientes, como yo me encuentro en Perú, aquí voy a modificar
la zona horaria por América/Lima, si no Laravel usará un sistema horario
totalmente distinto, entonces, actualizamos y teniendo la consola de
Chrome abierta en el lado izquierdo vamos a registrar un pensamiento, el pensamiento se registra visualmente aquí pero no hay ninguna petición que se está realizando. Hace un momento por más que intentábamos
registrar un nuevo pensamiento, luego de haber añadido Axios, no podíamos ver aquí en la pestaña Network el resultado de la petición, esto se debía a que el navegador ha estado usando una versión antigua del archivo Javascript porque estaba guardando esta versión antigua en la memoria caché del navegador, para desactivar esta memoria caché pueden hacer clic sobre este checkbox y ya no tendrán ese inconveniente.
Muy bien, entonces aquí vamos a actualizar, voy a escribir un nuevo pensamiento y esto que vemos aquí como Preview es lo que nos responde la API, es lo que nos
responde el servidor, nos da una respuesta en json con información del
nuevo registro que se acaba de crear. Entonces, usando esto es que nosotros debemos generar aquí el nuevo pensamiento, si nos vamos a la consola, aquí de hecho vamos a ver toda esta información, esta es la respuesta que Axios pone a nuestra disposición y aquí tenemos data, este data es lo que nos
está respondiendo realmente al servidor, todo lo demás lo añade Axios como información de la solicitud que hemos hecho. Entonces aquí vamos a hacer lo siguiente: ya no tenemos que definir nosotros
mismos una variable thought, sino que más bien sino que más bien este objeto thought lo podemos obtener a partir de la respuesta del servidor, entonces, una vez que se haya confirmado el registro exitoso, vamos a emitir el evento new para
actualizar el componente más general, con esto tendríamos el registro implementado e iremos ahora a nuestro componente más general para que cuando cargue este componente inicialmente no tengamos ningún pensamiento, sino que estos pensamientos se carguen desde la base de datos, nosotros actualmente en nuestra tabla tenemos este registro que acabamos de registrar hace un momento usando Axios, vamos a usar también Axios para obtener el listado de pensamientos en formato json, esto lo hemos programado antes en nuestro controlador haciendo un return de todos los registros del modelo thoughts, entonces, vamos a hacer una petición a esta ruta y según lo que la base datos nos devuelva vamos a mostrarlos aquí en la aplicación.
Entonces, dentro de data, thoughts estará
inicialmente vacío pero aquí una vez que haya cargado el componente, nosotros haremos una petición GET a través de Axios a esta ruta, no necesitamos pasarle ningún parámetro y una vez que obtengamos una respuesta, nosotros vamos a asignar un valor a nuestro arreglo de pensamientos, a partir de la data que el servidor nos devuelve, vamos a actualizar, y esta información que aquí estamos teniendo ya está viniendo de la base de datos, lo podemos confirmar porque aquí la fecha ahora incluso nos muestra hasta la hora, justamente hoy es 2 del mes 5 y son las 8 de la mañana en Perú, vamos a registrar un nuevo dato y vamos a actualizar la página, vemos ahora que la data está persistiendo en nuestra base de datos, ya tenemos registro y ya tenemos listado, nos falta editar y eliminar para terminar completamente nuestro CRUD, la idea a seguir es la misma, vamos en este caso a ThoughtComponent, aquí tenemos delete y aquí tenemos update, podemos hacer las peticiones Axios aquí o podemos hacerlas acá, en este caso vamos a hacer aquí las
peticiones y vamos a emitir los eventos para que se actualice la información en
el componente más general una vez que se ha realizado la operación en la base de datos.
Entonces, para actualizar diremos lo
siguiente: axios.put aquí tendremos thoughts y luego de thoughts tendremos aquí el id, el id del pensamiento que queremos editar, en este caso sería this.thought.id y entonces una vez que obtengamos una respuesta nosotros vamos a detener el modo de edición y vamos a emitir el update hacia el
componente más general, aquí podemos también enviar la información del nuevo pensamiento o sea que cuando se haga una actualización, vamos a devolver el objeto
thought con sus datos actualizados y cuando se haga un delete, cuando se presiona el botón de eliminar, nosotros haremos una petición de tipo delete a
esta misma ruta y una vez que obtengamos una respuesta, vamos a emitir el evento delete, de hecho aquí no estamos usando response para nada, por lo tanto, no necesitamos ese parámetro. Muy bien, entonces ahora, actualizamos, tenemos aquí estos dos pensamientos, vamos a eliminar "abc", actualizamos, ya no existe más "abc", vamos a editar este que dice "q", vamos a ponerle esto de aquí, voy a presionar guardar cambios y al parecer hemos obtenido un error, nos vamos a la pestaña de Network, vamos
a hacer de nuevo la petición y aquí tenemos este problema, nos dice que la columna description no puede ser null, lo que pasa es que aquí en nuestra petición
PUT, no estamos pasando ningún parámetro, pero ahora lo vamos a añadir, vamos a enviar aquí la descripción del pensamiento capturando lo que el usuario haya escrito aquí en este input de edición.
Entonces actualizamos, voy a escribir aquí: "Un pensamiento verdadero", bueno, aquí nos faltó el this, this siempre para poder acceder a la data, vamos a editar aquí y como vemos, esto se acaba de actualizar correctamente, el servidor de hecho nos ha respondido con la fecha de creación y además con una fecha de actualización, ¿sí?, o sea que si nosotros queremos podemos mostrar también la fecha de la última actualización, para ello simplemente tendríamos que hacer lo siguiente aquí dice "Publicado en" y nosotros vamos a añadir "Última actualización" y vamos a mostrar aquí updated_at, entonces actualizamos y aquí tenemos un pensamiento verdadero que se publicó
originalmente en esta fecha pero que se actualizó posteriormente siete minutos
más tarde, si nosotros creamos un nuevo pensamiento, tenemos que tanto la fecha de registro como de actualización son las mismas podríamos poner una condición para que si son iguales ya no muestre la actualización, pero eso son detalles que se pueden ir incorporando.
Ahora mismo nos hemos demorado porque es el primer CRUD que estamos creando y lo hemos hecho paso a paso, conforme se adquiera mayor práctica podremos crear aplicaciones mucho más interactivas y de hecho no aplicar Vue solamente a una página sino a cada una de las secciones que nuestra
aplicación requiera o inclusive, si queremos que la aplicación completa sea
totalmente interactiva, podríamos apoyarnos de otras bibliotecas para
configurar un sistema de rutas con Vue, ahora mismo ya tenemos un CRUD completamente funcional usando Laravel y usando Vue. Si les ha parecido un poco confuso esta sintaxis, esta sintaxis de aquí o incluso esta sintaxis de acá que
ya ni siquiera usa la palabra function al inicio, les invito a tomar el curso de Javascript básico que recientemente he publicado, si siguen ese curso, todo el código de aquí les parecerá muy entendible porque en este curso vamos a ver desde cero distintas características que presenta el lenguaje Javascript.
Además, este vídeo es una introducción
para que más adelante podamos crear aplicaciones mucho más complejas,
usando Vue y Laravel, así que, si este vídeo te ha parecido interesante, te ha resultado de ayuda de alguna forma, te agradecería muchísimo
que me ayudes a compartirlo con la intención de poder publicar más vídeos
de este tipo aquí en el canal.
Asimismo, si todavía no estás suscrito, te invito a
que te suscribas y puedas estar al tanto de más novedades que voy a estar
compartiendo por aquí en el canal. Bueno, gracias y hasta la próxima..