# Vue.js en Laravel
En las últimas versiones de Laravel (en este caso la versión 5.8) está preconfigurado Vue.js, por lo tanto comenzaremos de cero con un nuevo proyecto: Documentación oficial
Requisitos:
- Tener instalado Node.js en su pc.
- Tener conocimientos de Vue.js Revisar curso gratis aquí
# Intalaciones
Crear proyecto de Laravel:
laravel new vue-laravel-v1
Viajamos dentro de la carpeta y creamos la autenticación:
php artisan make:auth
Podemos notar que en la raiz de nuestro proyecto contamos con un archivo package.json
el cual cuenta con las siguientes dependencias:
"devDependencies": {
"axios": "^0.19",
"bootstrap": "^4.1.0",
"cross-env": "^5.1",
"jquery": "^3.2",
"laravel-mix": "^4.0.7",
"lodash": "^4.17.5",
"popper.js": "^1.12",
"resolve-url-loader": "^2.3.1",
"sass": "^1.15.2",
"sass-loader": "^7.1.0",
"vue": "^2.5.17"
}
Por lo tanto para instalar cada una de ellas solo debemos ejecutar:
npm i
Con esto ya tenemos configurado vue.js
dentro de nuestro proyecto
# Componentes
Vue ya viene con un componente de ejemplo el cual podemos utilizar de inmediato, puedes encontrarlo en: ./resources/js/components
Vamos a modificar la página de inicio para pintar este componente: ./resources/views/welcome.blade.php
@extends('layouts.app')
@section('content')
<example-component></example-component>
@endsection
Ahora, aparte de ejecutar nuestro servidor con php artisan serve
, necesitamos estar pendientes de los cambios en Javascript, por lo tanto también en paralelo ejecutaremos:
npm run watch
Cada vez que realizamos un cambio nos aparece un mensaje de Laravel, este lo puedes omitir agregando el siguiente código al archivo: webpack.mix.js
mix.disableNotifications();
# Práctica: Bases de datos
En este apartado desarrollaremos o más bien complementaremos nuestra práctica de notas con vue.js, por lo tanto configuraremos la base de datos, modelos, migraciones y controladores:
.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_auth
DB_USERNAME=root
DB_PASSWORD=
AppServiceProvider
use Illuminate\Support\Facades\Schema;
public function boot()
{
Schema::defaultStringLength(191);
}
Crear modelo y Migración
php artisan make:model Nota -m
Schema::create('notas', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('nombre');
$table->text('descripcion');
$table->bigInteger('user_id')->unsigned();
$table->foreign('user_id')->references('id')->on('users');
$table->timestamps();
});
Ojo aquí estamos utilizando claves foráneas para relacionar las notas con un usuario específico. Tutorial aquí
Ejecutar migraciones
php artisan migrate
Resource Controllers
php artisan make:controller NotaController --resource
web.php
Route::resource('/notas', 'NotaController')->middleware('auth');
# CRUD Controlador
Mostrar notas:
public function index(Request $request)
{
if($request->ajax()){
return Nota::where('user_id', auth()->id())->get();
}else{
return view('home');
}
}
Guardar nueva nota:
public function store(Request $request)
{
$nota = new Nota();
$nota->nombre = $request->nombre;
$nota->descripcion = $request->descripcion;
$nota->user_id = auth()->id();
$nota->save();
return $nota;
}
Editar nota:
public function update(Request $request, $id)
{
$nota = Nota::find($id);
$nota->nombre = $request->nombre;
$nota->descripcion = $request->descripcion;
$nota->save();
return $nota;
}
Eliminar nota:
public function destroy($id)
{
$nota = Nota::find($id);
$nota->delete();
}
# Vista Home
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">App de notas</div>
<div class="card-body">
<notas />
</div>
</div>
</div>
</div>
</div>
@endsection
# Componente con Vue.js
TareasComponent.vue
<template>
<div>
<form @submit.prevent="editarNota(nota)" v-if="modoEditar">
<h3>Editar nota</h3>
<input type="text" class="form-control mb-2"
placeholder="Nombre de la nota" v-model="nota.nombre">
<input type="text" class="form-control mb-2"
placeholder="Descripción de la nota" v-model="nota.descripcion">
<button class="btn btn-warning" type="submit">Editar</button>
<button class="btn btn-danger" type="submit"
@click="cancelarEdicion">Cancelar</button>
</form>
<form @submit.prevent="agregar" v-else>
<h3>Agregar nota</h3>
<input type="text" class="form-control mb-2"
placeholder="Nombre de la nota" v-model="nota.nombre">
<input type="text" class="form-control mb-2"
placeholder="Descripción de la nota" v-model="nota.descripcion">
<button class="btn btn-primary" type="submit">Agregar</button>
</form>
<hr>
<h3>Lista de notas:</h3>
<ul class="list-group">
<li class="list-group-item"
v-for="(item, index) in notas" :key="index" >
<span class="badge badge-primary float-right">
{{item.updated_at}}
</span>
<p>{{item.nombre}}</p>
<p>{{item.descripcion}}</p>
<p>
<button class="btn btn-warning btn-sm"
@click="editarFormulario(item)">Editar</button>
<button class="btn btn-danger btn-sm"
@click="eliminarNota(item, index)">Eliminar</button>
</p>
</li>
</ul>
</div>
</template>
<script>
export default {
data() {
return {
notas: [],
modoEditar: false,
nota: {nombre: '', descripcion: ''}
}
},
created(){
axios.get('/notas').then(res=>{
this.notas = res.data;
})
},
methods:{
agregar(){
if(this.nota.nombre.trim() === '' || this.nota.descripcion.trim() === ''){
alert('Debes completar todos los campos antes de guardar');
return;
}
const notaNueva = this.nota;
this.nota = {nombre: '', descripcion: ''};
axios.post('/notas', notaNueva)
.then((res) =>{
const notaServidor = res.data;
this.notas.push(notaServidor);
})
},
editarFormulario(item){
this.nota.nombre = item.nombre;
this.nota.descripcion = item.descripcion;
this.nota.id = item.id;
this.modoEditar = true;
},
editarNota(nota){
const params = {nombre: nota.nombre, descripcion: nota.descripcion};
axios.put(`/notas/${nota.id}`, params)
.then(res=>{
this.modoEditar = false;
const index = this.notas.findIndex(item => item.id === nota.id);
this.notas[index] = res.data;
})
},
eliminarNota(nota, index){
const confirmacion = confirm(`Eliminar nota ${nota.nombre}`);
if(confirmacion){
axios.delete(`/notas/${nota.id}`)
.then(()=>{
this.notas.splice(index, 1);
})
}
},
cancelarEdicion(){
this.modoEditar = false;
this.nota = {nombre: '', descripcion: ''};
}
}
}
</script>
# app.js
require('./bootstrap');
window.Vue = require('vue');
Vue.component('example-component', require('./components/ExampleComponent.vue').default);
Vue.component('tareas', require('./components/TareasComponent.vue').default);
const app = new Vue({
el: '#app',
});