Espera un momento ...
¿Te gustaría llevar mi curso de Laravel, gratis?
Sólo debes ingresar tus datos:
Lo que vamos a hacer, respecto a cómo lo ve el usuario de la aplicación, es lo siguiente.
El usuario tiene una imagen de perfil por defecto.
El usuario hace clic sobre su imagen de perfil, y de pronto puede seleccionar una nueva imagen (aunque también puede presionar cancelar y no pasa nada).
Si el usuario selecciona una imagen y acepta, entonces su imagen de perfil se actualiza inmediatamente (sin necesidad de recargar la página los cambios se mantienen).
Tenemos muchas formas de implementar esta característica.
En este caso lo haremos de la siguiente manera:
file
.click
sobre la imagen de perfil. Cuando se detecte este evento, vamos a provocar un click sobre el input de tipo file
.change
del input, para que cuando se haya escogido un archivo, realicemos una petición AJAX para modificar la imagen de perfil.El formulario oculto estará escondido gracias a una propiedad de CSS llamada display
(con el valor none
).
En este caso, lo estoy ubicando justo antes de la imagen.
<form action="{{ url('perfil/foto') }}" method="post" style="display: none" id="avatarForm">
{{ csrf_field() }}
<input type="file" id="avatarInput" name="photo">
</form>
<img src="{{ auth()->user()->getAvatarUrl() }}" id="avatarImage">
Nótese que:
file
tiene un atributo name con el valor photo
(este valor debe coincidir con lo que tengamos en nuestro controlador, para recuperar el archivo subido correctamente desde backend).class
, alt
y title
a mi imagen (ustedes pueden usar estos atributos según les convenga en sus proyectos).¿Qué hacemos con Javascript?
Como ya lo he comentado antes, necesitamos registrar 2 eventos. Y así mismo obtener una referencia de los elementos.
$(function () {
var $avatarImage, $avatarInput, $avatarForm;
$avatarImage = $('#avatarImage');
$avatarInput = $('#avatarInput');
$avatarForm = $('#avatarForm');
$avatarImage.on('click', function () {
$avatarInput.click();
});
$avatarInput.on('change', function () {
alert('change');
});
});
Como habrás notado, en el evento change
del input sólo he puesto un alerta.
Hasta este punto debes asegurarte de obtener ese alerta, luego de hacer clic en la imagen y seleccionar un archivo.
Si todo está conforme, entonces ya puedes reemplazar el alert
para realizar la petición Ajax.
Así tendríamos lo siguiente:
$avatarInput.on('change', function () {
var formData = new FormData();
formData.append('photo', $avatarInput[0].files[0]);
$.ajax({
url: $avatarForm.attr('action') + '?' + $avatarForm.serialize(),
method: $avatarForm.attr('method'),
data: formData,
processData: false,
contentType: false
}).done(function (data) {
if (data.success)
$avatarImage.attr('src', data.path);
}).fail(function () {
alert('La imagen subida no tiene un formato correcto');
});
});
Aquí debemos tener en cuenta que:
method
a partir de los valores definidos en el formulario.FormData
para subir la imagen vía Ajax (ya que el método serialize
en este caso sólo captura el csrf token
).data
y que tiene 2 atributos (success
para indicar si la operación tuvo éxito, y path
con la ruta hacia la imagen de perfil).Por último, sólo nos hace falta tener registrada la ruta perfil/foto
(que fue la que usamos en el action
del formulario). Si lo prefieres, puedes usar una ruta distinta.
Esta ruta debe declararse en el archivo de rutas de Laravel.
Route::post('/perfil/foto', 'ProfileController@updatePhoto');
En este caso, la ruta se resuelve a través de un controlador llamado ProfileController
. Específicamente a través de su método updatePhoto
.
Es así que tendríamos lo siguiente en dicho controlador:
public function updatePhoto(Request $request)
{
$this->validate($request, [
'photo' => 'required|image'
]);
$file = $request->file('photo');
$extension = $file->getClientOriginalExtension();
$fileName = auth()->id() . '.' . $extension;
$path = public_path('images/users/'.$fileName);
Image::make($file)->fit(144, 144)->save($path);
$user = auth()->user();
$user->photo_extension = $extension;
$saved = $user->save();
$data['success'] = $saved;
$data['path'] = $user->getAvatarUrl() . '?' . uniqid();
return $data;
}
Este método:
photo
enviado en la petición sea una imagen (y es un además un campo obligatorio).Image
para que si la imagen es mayor a 144x144 píxeles, entonces se ajuste su tamaño en función a este límite.photo_extension
, la extensión de la imagen subida.Para que el código anterior funcione correctamente, es necesario que en la tabla de usuarios tengas una columna photo_extension
.
$table->string('photo_extension')->nullable();
También es necesario que definas el método getAvatarUrl
en el modelo User
.
public function getAvatarUrl()
{
if ($this->photo_extension)
return asset('images/users/'.$this->id.'.'.$this->photo_extension);
return asset('images/users/default.jpg');
}
Este método devuelve una URL absoluta hacia la imagen de perfil del usuario. Y en caso de no existir, la URL absoluta de una imagen por defecto.
Si no has instalado aún el paquete Intervention/Image (necesario para que funcione la redimensión de imágenes), lo puedes instalar simplemente ejecutando:
composer require intervention/image
Por cierto. Si eres observador habrás notado el uso de uniqid()
en el método updatePhoto
. Éste método se usa para añadir un número único al final del nombre del archivo, y asegurar de esta forma, que el usuario vea siempre su nueva imagen de perfil (ya que es posible que anteriormente haya subido una imagen con la misma extensión, y que esta imagen se haya guardado en la memoria caché del navegador).
Este artículo lo he escrito en conmemoración a un par de videos que grabé ya hace un buen tiempo sobre el mismo tema.
Si prefieres, puedes seguir el tutorial en formato de video. Aunque, debes tener en cuenta que hay ligeras diferencias respecto al video y este tutorial escrito.
Comparte este post si te fue de ayuda 🙂.
Regístrate
Accede a todos los cursos, y resuelve todas tus dudas.
Cursos Recomendados
Aprende Laravel desde cero y desarrolla aplicaciones web reales, en tiempo récord, de la mano de Laravel.
Iniciar cursoActualiza tus proyectos desde cualquier versión hasta la última versión estable de Laravel.
Iniciar cursoDesarrollemos un Messenger! Aprende sobre Channels, Queues, Vuex, JWT, Sesiones, BootstrapVue y mucho más.
Iniciar cursoEspera un momento ...
¿Te gustaría llevar mi curso de Laravel, gratis?
Sólo debes ingresar tus datos: