CRUD con Laravel y Vue.js 3

Continuamos con esta serie de post donde enseñamos como hacer un CRUD con laravel y Vue.js. En esta entrada vamos a crear nuestro segundo componente que será el encargado de mostrar los productos que hay en la base de datos, lo llamaremos ProductComponent.vue

Crud laravel y vue.js
<template>
    <div class="card" style="margin-bottom: 25px">
        <div class="panel-heading">Publicado en {{ product.created_at }} - Última actualización: {{ product.updated_at }}</div>

        <div class="card-body">
 
            <input v-if="editMode" type="text" class="form-control" v-model="product.reference">
            <p v-else>{{ product.reference }}</p>

            <input v-if="editMode" type="text" class="form-control" v-model="product.category">
            <p v-else>{{ product.category }}</p>

            <input v-if="editMode" type="text" class="form-control" v-model="product.cost">
            <p v-else>{{ product.cost }}</p>

            <input v-if="editMode" type="text" class="form-control" v-model="product.quantity">
            <p v-else>{{ product.quantity }}</p>
 
        </div>

        <div class="card-footer" >
            <button v-if="editMode" class="btn btn-success" v-on:click="onClickUpdate()">
                Guardar cambios
            </button>
            <button v-else class="btn btn-primary" v-on:click="onClickEdit()">
                Editar
            </button>

            <button class="btn btn-danger" v-on:click="onClickDelete()">
                Eliminar
            </button>
        </div>
    </div>
</template>

<script>
    export default {
        props: ['product'],
        data() {
            return {
                editMode: false
            };
        },
        mounted() {
            console.log('Component product mounted.')
        },
        methods: {
            onClickDelete() {
                axios.delete(`/eliminar-producto/${this.product.id}`).then(() => {
                    this.$emit('delete');
                });
            },
            onClickEdit() {
                this.editMode = true;
            },
            onClickUpdate() {
                const params = {
                    reference: this.product.reference,
                    category: this.product.category,
                    cost: this.product.cost,
                    quantity: this.product.quantity
                };
                axios.put(`/actualizar-producto/${this.product.id}`, params).then((response) => {
                    this.editMode = false;
                    const product = response.data;
                    this.$emit('update', product);
                });
            }
        }
    }
</script>

Vamos a explicar un poco el código, dentro de los inputs donde se puede ver v-if="editMode" codigo de Vue.js que nos hacen de if como los de php o cualquier otro lenguaje. y donde podeis, ver dentro de las etiquetas <p> del codigo superior, usamos v-else para completar estos if. y no dicen otra cosa que si la variable editMode es true que se muestre el input v-if="editMode" y si no v-else hace que se muestre el parrafo y lo definimos primero a false en la función data() de nuestro componente. Por que al clicar en el boton de editar se ejecutará la función v-on:click=”onClickEdit()” que hará que nuestra variable editMode pase a true y cambie el comportamiento del componente. Al estar la variable editMode en true despues de clicar en el botón de editar, este se ocultará el botón de guardar cambios el cual tiene un evento click de Vue que ejecutarála funcion onClickUpdate() dentro de methods y recogeremos los valores que haya en los campos del formulario y con axios enviamos una petición HTTP al backend para que actualice los datos enviados.

axios.put(`/actualizar-producto/${this.product.id}`, params).then((response) => {
                    this.editMode = false;
                    const product = response.data;
                    this.$emit('update', product);
                });

Volvemos a poner a la variable editMode a false, para que desaparezcan los campos de formulario y vuelvan a aparecer solo los datos y volvemos a emitir un evento this.$emit('update', product); (donde “update” es el nombre del evento y “product” los datos a pasar) que será recogido en el ultimo componente que será el encargado de mostrar, actualizar o eliminar los datos del documento HTML.

El tercer y último componente lo llamaremos MyProductsComponent.vue y este es el código

<template> 
<div class="col-md-10">      

    <!-- @new="addProduct" esd la escucha del evento addProduct que se emite de la forma this.$emit('new', product); en FormComponent  -->
     <form-component @new="addProduct"></form-component> 

    <!-- v-for es un blucle en Vue le decimos que itere cada product de products
         con :product="product" le decimos que en el componente <product-component>
         haya una variable llamada product con la info de cada product 
         indicamos que la :key que envie al conmtrollador para eliminar sea la id -->
    <product-component
        v-for="(product, index) in products"
        :key="product.id"
        :product="product" 
        
        @update="updateProduct(index, ...arguments)"
        @delete="deleteProduct(index)"> 
    </product-component>

        
    </div>
</template>

<script>
    export default {
        data() {
            return {
                products: []
            }
        },
        mounted() {
            axios.get('/todos-productos').then((response) => {
                this.products = response.data;
                console.log(response.data)
            });
        },
        methods: {
            addProduct(product) {
                this.products.push(product);
            },
            updateProduct(index, product) {
                this.products[index] = product;
            },
            deleteProduct(index) {
                this.products.splice(index, 1);
            }
        }
    }
</script>

Como se aprecia en el código incluimos en este componente el componente  <form-component @new="addProduct"></form-component> , este componente lo creamos en el capítulo anterior y este emitia un evento, pues la manera que tiene Vue.js de estar a la escucha ese evento en este nuevo componente es añadiendo @new="addProduct" a la etiqueta de <form-component>, de esta manera cada vez que el evento new salte será recogido por MyProductComponent.vue y ejecutará el metodo addProduct(product) añadiendo el nuevo producto en el objeto de productos declarado en la función data() de esta manera this.products.push(product);

Seguimos con el código, tambien incluimos el componente ProductComponent.vue

<product-component
        v-for="(product, index) in products"
        :key="product.id"
        :product="product" 
        
        @update="updateProduct(index, ...arguments)"
        @delete="deleteProduct(index)"> 
    </product-component>

Vamos a explicarlo con mas detenimiento, cuando se carga este componente se ejecutan las funciones data() y mounted(), la primera ya la conocemos pero la función mounted() es la que le carga los datos al componente y en este caso haciendo una petición GET mediante axios.get() al servidor obteniendo todos los productos de la base de datos e introduciendolos en el array de objetos products de la función data(),

v-for="(product, index) in products" aqui lo unico que le decimos a Vue es que itere con un bucle for cada producto con su indice que hay en el array products.

:key="product.id" aqui decimos que la key que usaremos de id para editar o eliminar sea la id del producto no hace falta que lo gestionemos nosotros, Vue se encarga de ello.

:product="product" y aqui decimos que la variable a usar en el componente es product.

De esta manera tan sencilla se crearán tantos componentes de ProductComponent como productos haya en la base de datos

 @update="updateProduct(index, ...arguments)"        @delete="deleteProduct(index)"  y aqui como imaginas le estamos poniendo a la escucha de los eventos update y delete del ProductComponent.vue y ejecute las consecuentes funciones dentro de methods que son las encargadas de eliminar y actualizar el producto.

Y ya por ultimo nos queda registrar nuestros componentes en el archivo resources/app.js de esta manera,

Vue.component('form-component', require('./components/FormComponent.vue').default);
Vue.component('product-component', require('./components/ProductComponent.vue').default);
Vue.component('my-products-component', require('./components/MyProductsComponent.vue').default);

Ya solo tendremos que ir a algunas de nuestras plantillas Blade e incluir la etiqueta del componente padre y que cargen los componentes hijos y su logica.