Formulaire modal
! Nouvelle version pour Laravel 5.2 !
On m’a souvent posé la question concernant la création d’un formulaire modal avec Bootstrap et également son interaction avec Laravel. Je vais donc dans cet article développer cet aspect en partant d’une installation toute fraiche de Laravel et en la modifiant un peu pour permettre l’enregistrement des utilisateurs à partir d’un formulaire modal.
Donc commencez par installer un Laravel 5.2 tout neuf par votre méthode préférée (l’installateur, composer…). Créez aussi une base de données pour que ça fonctionne. N’oubliez pas de changer le nom du fichier d’environnement (.env.example => .env) en mentionnant correctement les références de la base.
Vous devez vous retrouver avec le contrôleur pour l’authentification :
Comme Laravel 5.2 ne comporte pas les vues, routes et autres pour l’authentification il faut les générer avec la commande :
php artisan make:auth
Vous devez alors avoir ces vues :
Le contrôleur
Voici le code du contrôleur Authcontroller modifié :
<?php namespace App\Http\Controllers\Auth; use App\User; use Validator; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\ThrottlesLogins; use Illuminate\Foundation\Auth\AuthenticatesAndRegistersUsers; use Illuminate\Http\Request; class AuthController extends Controller { /* |-------------------------------------------------------------------------- | Registration & Login Controller |-------------------------------------------------------------------------- | | This controller handles the registration of new users, as well as the | authentication of existing users. By default, this controller uses | a simple trait to add these behaviors. Why don't you explore it? | */ use AuthenticatesAndRegistersUsers, ThrottlesLogins; /** * Where to redirect users after login / registration. * * @var string */ protected $redirectTo = '/'; /** * Create a new authentication controller instance. * * @return void */ public function __construct() { $this->middleware($this->guestMiddleware(), ['except' => 'logout']); } /** * Get a validator for an incoming registration request. * * @param array $data * @return \Illuminate\Contracts\Validation\Validator */ protected function validator(array $data) { return Validator::make($data, [ 'name' => 'required|max:255', 'email' => 'required|email|max:255|unique:users', 'password' => 'required|min:6|confirmed', ]); } /** * Create a new user instance after a valid registration. * * @param array $data * @return User */ protected function create(array $data) { return User::create([ 'name' => $data['name'], 'email' => $data['email'], 'password' => bcrypt($data['password']), ]); } /** * Handle a registration request for the application. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function register(Request $request) { $validator = $this->validator($request->all()); if ($validator->fails()) { $this->throwValidationException( $request, $validator ); } $this->create($request->all()); return response()->json(); } }
J’ai surchargé la méthode postRegister du trait pour changer le code en enlevant la connexion automatique et en renvoyant une réponse JSON. La validation tient compte du fait que la requête peut être en Ajax, donc en cas d’erreur de saisie on aura automatiquement un retour correct. Si tout va bien on crée l’utilisateur et on renvoie une réponse JSON vierge.
La vue app.blade.php
Voici le code complet de cette vue :
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Laravel</title> <!-- Fonts --> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.4.0/css/font-awesome.min.css" rel='stylesheet' type='text/css'> <link href="https://fonts.googleapis.com/css?family=Lato:100,300,400,700" rel='stylesheet' type='text/css'> <!-- Styles --> <link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css" rel="stylesheet"> {{-- <link href="{{ elixir('css/app.css') }}" rel="stylesheet"> --}} <style> body { font-family: 'Lato'; } .fa-btn { margin-right: 6px; } </style> </head> <body id="app-layout"> <nav class="navbar navbar-default navbar-static-top"> <div class="container"> <div class="navbar-header"> <!-- Collapsed Hamburger --> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#app-navbar-collapse"> <span class="sr-only">Toggle Navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <!-- Branding Image --> <a class="navbar-brand" href="{{ url('/') }}"> Laravel </a> </div> <div class="collapse navbar-collapse" id="app-navbar-collapse"> <!-- Left Side Of Navbar --> <ul class="nav navbar-nav"> <li><a href="{{ url('/home') }}">Home</a></li> </ul> <!-- Right Side Of Navbar --> <ul class="nav navbar-nav navbar-right"> <!-- Authentication Links --> @if (Auth::guest()) <li><a href="{{ url('/login') }}">Login</a></li> <li><a href="#" id="register">Register</a></li> @else <li class="dropdown"> <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"> {{ Auth::user()->name }} <span class="caret"></span> </a> <ul class="dropdown-menu" role="menu"> <li><a href="{{ url('/logout') }}"><i class="fa fa-btn fa-sign-out"></i>Logout</a></li> </ul> </li> @endif </ul> </div> </div> </nav> <div class="container"> <div class="alert alert-success alert-dismissible hidden"> You are now registered, you can login. </div> </div> @yield('content') <!-- Modal --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">Register</h4> </div> <div class="modal-body"> <form id="formRegister" class="form-horizontal" role="form" method="POST" action="{{ url('register') }}"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> <div class="form-group"> <label class="col-md-4 control-label">Name</label> <div class="col-md-6"> <input type="text" class="form-control" name="name"> <small class="help-block"></small> </div> </div> <div class="form-group"> <label class="col-md-4 control-label">E-Mail Address</label> <div class="col-md-6"> <input type="email" class="form-control" name="email"> <small class="help-block"></small> </div> </div> <div class="form-group"> <label class="col-md-4 control-label">Password</label> <div class="col-md-6"> <input type="password" class="form-control" name="password"> <small class="help-block"></small> </div> </div> <div class="form-group"> <label class="col-md-4 control-label">Confirm Password</label> <div class="col-md-6"> <input type="password" class="form-control" name="password_confirmation"> </div> </div> <div class="form-group"> <div class="col-md-6 col-md-offset-4"> <button type="submit" class="btn btn-primary"> Register </button> </div> </div> </form> </div> </div> </div> </div> <!-- JavaScripts --> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script> <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> <script> $(function(){ $('#register').click(function() { $('#myModal').modal(); }); $(document).on('submit', '#formRegister', function(e) { e.preventDefault(); $('input+small').text(''); $('input').parent().removeClass('has-error'); $.ajax({ method: $(this).attr('method'), url: $(this).attr('action'), data: $(this).serialize(), dataType: "json" }) .done(function(data) { $('.alert-success').removeClass('hidden'); $('#myModal').modal('hide'); }) .fail(function(data) { $.each(data.responseJSON, function (key, value) { var input = '#formRegister input[name=' + key + ']'; $(input + '+small').text(value); $(input).parent().addClass('has-error'); }); }); }); }) </script> {{-- <script src="{{ elixir('js/app.js') }}"></script> --}} </body> </html>
Nous allons analyser un peu tout ça…
Le formulaire
La première chose à prévoir est le formulaire d’enregistrement :
<!-- Modal --> <div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button> <h4 class="modal-title" id="myModalLabel">Register</h4> </div> <div class="modal-body"> <form id="formRegister" class="form-horizontal" role="form" method="POST" action="{{ url('/auth/register') }}"> <input type="hidden" name="_token" value="{{ csrf_token() }}"> <div class="form-group"> <label class="col-md-4 control-label">Name</label> <div class="col-md-6"> <input type="text" class="form-control" name="name"> <small class="help-block"></small> </div> </div> <div class="form-group"> <label class="col-md-4 control-label">E-Mail Address</label> <div class="col-md-6"> <input type="email" class="form-control" name="email"> <small class="help-block"></small> </div> </div> <div class="form-group"> <label class="col-md-4 control-label">Password</label> <div class="col-md-6"> <input type="password" class="form-control" name="password"> <small class="help-block"></small> </div> </div> <div class="form-group"> <label class="col-md-4 control-label">Confirm Password</label> <div class="col-md-6"> <input type="password" class="form-control" name="password_confirmation"> </div> </div> <div class="form-group"> <div class="col-md-6 col-md-offset-4"> <button type="submit" class="btn btn-primary"> Register </button> </div> </div> </form> </div> </div> </div> </div>
A ce niveau il n’y a rien de bien particulier, c’est le code classique d’une page modale de Bootstrap.
Le Javascript
Voici le Javascript que j’ai prévu :
@section('scripts') <script> $(function(){ $('#register').click(function() { $('#myModal').modal(); }); $(document).on('submit', '#formRegister', function(e) { e.preventDefault(); $('input+small').text(''); $('input').parent().removeClass('has-error'); $.ajax({ method: $(this).attr('method'), url: $(this).attr('action'), data: $(this).serialize(), dataType: "json" }) .done(function(data) { $('.alert-success').removeClass('hidden'); $('#myModal').modal('hide'); }) .fail(function(data) { $.each(data.responseJSON, function (key, value) { var input = '#formRegister input[name=' + key + ']'; $(input + '+small').text(value); $(input).parent().addClass('has-error'); }); }); }); }) </script> @endsection
La première chose est l’ouverture de la feuille modale lorsqu’on clique l’option Register de la barre de menu :
$('#register').click(function() { $('#myModal').modal(); });
On a alors la présentation du formulaire modal :
On doit s’intéresser ensuite à la soumission :
$(document).on('submit', '#formRegister', function(e) { e.preventDefault(); $('input+small').text(''); $('input').parent().removeClass('has-error'); $.ajax({ method: $(this).attr('method'), url: $(this).attr('action'), data: $(this).serialize(), dataType: "json" }) .done(function(data) { // Action en cas de réussite }) .fail(function(data) { // Action en cas d'échec }); });
On commence par effacer les références éventuelles des erreurs précédentes et on lance la requête en Ajax.
En cas d’erreur dans la saisie on a :
.fail(function(data) { $.each(data.responseJSON, function (key, value) { var input = '#formRegister input[name=' + key + ']'; $(input + '+small').text(value); $(input).parent().addClass('has-error'); }); });
On passe en revue toutes les erreurs et on les rend visibles sur le formulaire. On reçoit ce genre de JSON de la part du contrôleur :
{"name":["The name field is required."],"password":["The password field is required."]}
Et donc cet aspect :
Si la validation est correcte c’est ce code qui est activé :
.done(function(data) { $('.alert-success').removeClass('hidden'); $('#myModal').modal('hide'); })
On rend visible la barre d’information pour l’utilisateur :
On pourrait adopter une autre stratégie en connectant directement l’utilisateur, là j’ai préféré l’obliger à entrer ses informations.
Pour terminer on cache la feuille modale et c’est terminé !
9 commentaires
bestmomo
Voici la fonction register pour Laravel à partir de 5.5 :
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
return response()->json();
}
Il faut ajouter ce use :
use Illuminate\Auth\Events\Registered;
webwatson
le button submit de passe pas chez moi. Quand je clic rien ne se passe
bestmomo
Le Javascript n’est pas déclenché ?
webwatson
C’est déclenché! Mais dans la console j’ai une erreur de type 500 :jquery.js:8630 POST http://localhost:8000/register 500 (Internal Server Error)
Quand je clique dessus j’ai cette description ci-dessous.
« message »: « Method App\\Http\\Controllers\\Auth\\RegisterController::throwValidationException does not exist. »,
« exception »: « BadMethodCallException »,
« file »: « C:\\Users\\SouklouMap\\laravelForm\\soukloumap_finale\\vendor\\laravel\\framework\\src\\Illuminate\\Routing\\Controller.php »,
« line »: 68,
« trace »: [
{
« file »: « C:\\Users\\SouklouMap\\laravelForm\\soukloumap_finale\\app\\Http\\Controllers\\Auth\\RegisterController.php »,
« line »: 83,
« function »: « __call »,
« class »: « Illuminate\\Routing\\Controller »,
« type »: « -> »
},
bestmomo
La méthode throwValidationException a disparu avec la version 5.5 de Laravel, donc c’est normal que ça ne fonctionne pas. il faudrait actualiser cet article.
webwatson
comment dois-je l’actualisé ? Je suis un débutant avec laravel.
John Smith
Bonsoir Momo,
Je souhaiterais généraliser ta méthode pour n’importe quel formulaire modal : avec des input mais aussi des textarea, voire autres…
Comment modifier le javascript pour qu’il tienne compte de tous les types d’éléments de formulaire ?
Je te remercie d’avance pour ta réponse.
Cordialement.
bestmomo
Salut,
Pour la soumission pas de souci, il n’y a aucun taitement particulier et tout passe.
Le seul problème peut se situer au niveau du traitement des erreurs de validation, si on utilise des boutons radio ou des cases à cocher il faut les sauter dans la boucle du fail en testant le type de l’input.
webwatson
le button submit de passe pas chez moi. Quand je clic rien ne se passe