Uno de los drag & drop de imágenes mas populares que existen en Javascript es Filepond. No solamente te permite la carga de imágenes, sino también todo tipo de archivo que quieras que el usuario cargue en tu pagina. En esta guía veremos como instalar Filepond en un proyecto de Laravel junto con Vue 2.0. Para comenzar a utilizar Filepond en Vue y Laravel vamos a instalar la extensión vue-filepond para que nos sirva como adaptador entre Filepond y Vue.

Descargar vue-filepond para Vue 2.0

npm install vue-filepond@^6.0.0

Instalar Extensión de Imagen Previa en Filepond

npm i filepond-plugin-image-preview --save

Agregar Extensión de Verificación de Archivos en Filepond

npm i filepond-plugin-file-validate-type

Ahora que ya tenemos instaladas todas las extensiones, vamos a configurar el archivo JS de nuestro proyecto para iniciar Filepond en Vue. En el caso de Laravel, se encuentra en resources/js/app.js. Cabe mencionar que ya tenemos instanciada una app de Vue 2.0:

import Vue from 'vue';
import vueFilePond from "vue-filepond";
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";

const FilePond = vueFilePond(
    FilePondPluginFileValidateType,
    FilePondPluginImagePreview
  );

const app = new Vue({
    el: '#app',
    components: {
        FilePond
    },
    data: {
        ...
    },
});

Justo debajo de importar Vue, agregamos vue-filepond junto con sus extensiones y dentro de la App, asignamos el componente de Filepond para poder utilizar en nuestros templates o en caso de Laravel dentro de Blade.

Configurando los Estilos de FilePond

Para configurar los estilos de Filepond en Vue, tenemos dos opciones. La primera es importar los estilos dentro de nuestro archivo JS y la segunda es incorporando en el HTML los estilos desde el CDN.

import "filepond/dist/filepond.min.css";  
import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css";

En Laravel, tenemos un archivo de estilos en resouces/css/app.css. En el caso de que no pongamos los estilos dentro del JS, escribimos lo siguiente en app.css.

@import "filepond/dist/filepond.min.css";
@import "filepond-plugin-image-preview/dist/filepond-plugin-image-preview.min.css";

y por ultimo, si ninguna de las dos opciones anteriores te parecen adecuadas, podes agregar en tu archivo HTML los estilos desde el CDN.

<link href="https://unpkg.com/filepond/dist/filepond.css" rel="stylesheet">
<link href="https://unpkg.com/filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css" rel="stylesheet">

Configurando Paginas de Backend (Laravel)

Esta parte es fácil de seguir, yo voy a usar PHP pero se van a entender los conceptos para que lo hagas en el lenguaje que estés utilizando. Recordemos que puede ser NodeJS, Python, Java, etc… Filepond necesita una url para poder cargar las imágenes, esta carga se hace mediante de un formulario con el método POST.

Creando el Controlador para subir Imágenes

Vamos a crear un controlador que se va a encargar de subir las imágenes o archivos al Storage y eliminarlas en caso de que el usuario cancele la acción de subir la imagen con Filepond.

php artisan make:controller UploadController
<?php

namespace App\Http\Controllers;

use App\Models\TemporaryFile;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Storage;

class UploadController extends Controller
{
    //
    public function __construct()
    {
        app('debugbar')->disable();
    }

    public function delete(Request $request)
    {
        $path = $request->getContent(); 
        $directory = '/tmp/'.dirname($path);
        
        Storage::deleteDirectory($directory);           
    }

    public function store(Request $request)
    {        
        if($request->hasFile('image')){
            $file = $request->file('image');
            $filename = $file->getClientOriginalName();
            $folder = uniqid() . '-' . now()->timestamp;
            $file->storeAs('tmp/'.$folder , $filename);
            $path = $folder."/".$filename;          
            return $path;
        }
        return '';
    }
}

La función de store que se encarga de guardar la imagen dentro del storage necesita devolver un string para que Filepond pueda seguir operando desde el formulario padre.

Ahora que ya tenemos creado nuestro controlador, vamos a crear las rutas necesarias para que el formulario de Filepond funcione con Vue y Laravel.

Creando Rutas para subir Imágenes

Necesitamos tener dos rutas una con el método POST y otra con el método DELETE. En mi caso voy a crear las dos rutas dentro de web con el middleware de Auth para que solamente los usuarios registrados puedan subir imágenes con filepond en Laravel.

<?php
    Route::middleware(['auth'])->group(function () {     
    Route::delete('/upload', [UploadController::class, "delete"]);
    Route::post('/upload', [UploadController::class, "store"]);
});

Componente (Opcional)

Si solamente tenés una sección de tu web que necesita tener un drag & drop junto con Laravel, Vue y Filepond no es necesario que hagas este paso. Solamente copiando el código que te voy a pasar a continuación dentro de tu archivo HTML (DIV ID : APP) es suficiente.

En este caso, para que sea mas fácil de leer, vamos a crear un componente en Laravel que se encargue de renderizar el componente de Vue. Vuelvo a decir que este paso no es obligatorio y podes manejarlo como acostumbres a tratar componentes de Vue.

php artisan make:component InputDragDrop
<?php

namespace App\View\Components;

use Illuminate\View\Component;

class InputDragDrop extends Component
{
    /**
     * Create a new component instance.
     *
     * @return void
     */

    public $name;
    public $url;

    public function __construct($name, $url)
    {
        $this->name = $name;
        $this->url = $url;
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\Contracts\View\View|string
     */
    public function render()
    {
        return view('components.input-drag-drop');
    }
}

Este nuevo componente toma acepta dos parámetros, uno para el nombre y otro para la URL donde se encuentra el POST. Ahora vamos a incorporar a la vista de este componente el componente de Vue con las traducciones al Español correspondientes. Lamentablemente no existe la manera de traducir Filepond desde la extensión de Vue con un archivo JSON, por lo que tendremos que modificar las label una por una. Por este motivo hago un componente aparte sino seria un quilombo tener que copiar y pegar todo este componente en donde quiera un drag & drop de imágenes en Laravel.

<file-pond class="mt-2"
    label-idle="Arrastra y suelta tus archivos o <span class = 'filepond--label-action'> Examinar <span>"
    label-invalid-field="El campo contiene archivos inválidos" label-file-waiting-for-size="Esperando tamaño"
    label-file-size-not-available="Tamaño no disponible" label-file-loading="Cargando"
    label-file-load-error="Error durante la carga" label-file-processing="Cargando"
    label-file-processing-complete="Carga completa" label-file-processing-aborted="Carga cancelada"
    label-file-processing-error="Error durante la carga" label-file-processing-revert-error="Error durante la reversión"
    label-file-remove-error="Error durante la eliminación" label-tap-to-cancel="Toca para cancelar"
    label-tap-to-retry="Tocar para volver a intentar" label-tap-to-undo="Tocar para deshacer"
    label-button-remove-item="Eliminar" label-button-abort-item-load="Abortar" label-button-retry-item-load="Reintentar"
    label-button-abort-item-processing="Cancelar" label-button-undo-item-processing="Deshacer"
    label-button-retry-item-processing="Reintentar" label-button-process-item="Cargar"
    label-max-file-size-exceeded="El archivo es demasiado grande"
    label-max-file-size="El tamaño máximo del archivo es {filesize}"
    label-max-total-file-size-exceeded="Tamaño total máximo excedido"
    label-max-total-file-size="El tamaño total máximo del archivo es {filesize}"
    label-file-type-not-allowed="Archivo de tipo no válido"
    file-validate-type-label-expected-types="Espera {allButLastType} o {lastType}"
    image-validate-size-label-format-error="Tipo de imagen no compatible"
    image-validate-size-label-image-size-too-small="La imagen es demasiado pequeña"
    image-validate-size-label-image-size-too-big="La imagen es demasiado grande"
    image-validate-size-label-expected-min-size="El tamaño mínimo es {minWidth} × {minHeight}"
    image-validate-size-label-expected-max-size="El tamaño máximo es {maxWidth} × {maxHeight}"
    image-validate-size-label-image-resolution-too-low="La resolución es demasiado baja"
    image-validate-size-label-image-resolution-too-high="La resolución es demasiado alta"
    image-validate-size-label-expected-min-resolution="La resolución mínima es {minResolution}"
    image-validate-size-label-expected-max-resolution="La resolución máxima es {maxResolution}"
    name="{{$name}}"
    accepted-file-types="image/jpeg, image/png" v-bind:server="{
                                                      url: '{{$url}}',
                                                      timeout: 7000,
                                                      process: {
                                                          method: 'POST',
                                                          headers: {
                                                              'X-CSRF-TOKEN': '{{ csrf_token() }}'
                                                          },
                                                      },
                                                      revert: {
                                                        method: 'DELETE',
                                                        headers: {
                                                            'X-CSRF-TOKEN': '{{ csrf_token() }}'
                                                        },
                                                      }
                                                    }" />

Ahora ya tenemos el componente, junto con FilePond en Español funcionando con Vue y Laravel. Nos queda un ultimo paso, agregar este drag & drop dentro de un formulario. Vamos a ir a nuestro archivo de Blade en donde tengamos un formulario POST. Ejemplo podría ser la carga de un articulo nuevo o logo para empresa.

 <form action="{{route('products.store')}}" method="POST">
    @csrf
    @method('POST')

    <x-input-drag-drop name="image" url="/upload"></x-input-drag-drop>
    
    <div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
        <a href="{{route('admin.products')}}" class="button-cancel mr-2">
            Cancelar
        </a>
        <button type="submit" class="button-save" name="submit">
            Guardar
        </button>
    </div>
    </div>
</form>

En name ponemos image y en url /upload que son las rutas que acabamos de crear. Al subir una imagen, nos va a crear la imagen que se suba dentro del Storage de Laravel y nos va a devolver el PATH o la ruta en donde se encuentra.

Al Enviar el formulario, pasara como parámetro una string con la ruta en donde se encuentra para que podamos guardarla en la Base de Datos, renombrarla o hacer lo cualquier cosa con ella.

Copyright © 2018-2020 Latirus. Todos los Derechos Reservados.