Laravel Livewire | Login & Dynamic Registration Form for Multiple Roles
In this tutorial, we’ll create a login and dynamic user registration form for multiple roles using Laravel Livewire package.
At the end of this tutorial you’ll be familiar with:
- Creating Components and views
- Including livewire assets and importing component into views
- Creating login and dynamic registration form
- Custom validation of form data and displaying errors.
- Validating data as per the selected role.
- Displaying flash message in response to user actions.
Note
Here is a tutorial on the installation and configuration of Laravel Livewire with example.
Begin with Creating Component
Create a component using the below command.
php artisan make:livewire CollegeLoginRegister.AuthComponent --inline
The attribute --inline
will only create a component class. You can see that our component class is created at app/Http/Livewire/CollegeLoginRegister/AuthComponent.php
.
First, look at our empty AuthComponent
with just a render() method and returns HTML not view.
<?php namespace App\Http\Livewire; use Livewire\Component; class AuthComponent extends Component { return <<<'blade' <div> {{-- Care about peoples approval and you will be their prisoner. --}} </div> blade; }
Next is to create a custom view for this component at resources/views/livewire/college-login-register/login-register.blade.php
. The view login-register.blade.php
contains both login and register form and through user clicks, we’ll navigate him across different forms.
Replace the render()
method code with below code.
public function render() { return view('livewire.college-login-register.login-register', []); }
Creating Main Entry Point for outputting component views
This is just a simple HTML page but you’ll be including livewire assets in here. Create a base view for displaying component contents at resources/views/livewire/college-login-register/base.blade.php
.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Laravel LiveWire Login & Register Application</title> @livewireStyles <link rel="stylesheet" href="{{ url('assets/css/bootstrap.min.css') }}"> <style> .error{ color: red; } </style> </head> <body> <!-- This is the correct way of importing component --> @livewire('college-login-register.auth-component') <!-- livewire('CollegeLoginRegister.AuthComponent') this does not work --> @livewireScripts <script src="{{ url('assets/js/jquery.min.js') }}"></script> <script src="{{ url('assets/js/popper.min.js') }}"></script> <script src="{{ url('assets/js/bootstrap.min.js') }}"></script> </body> </html>
Add @livewireStyles
for importing livewire CSS files and @livewireScripts
for importing livewire javascript files. These are mandatory and include livewire js files before any other js library.
Caution
While importing component inside @livewire('use-small-case-letter')
use smaller case else will throw Component Not Found Exception
Adding Web Routes
Update the routes/web.php
file with below route at the end.
// Livewire College login and registration routes Route::get('college', function(){ return view('livewire.college-login-register.base', []); });
Adding registration functionalities to AuthComponent
First, let’s start with creating and saving the registration form.
public $user = [ "role" => "student", "first_name" => "", "last_name" => "", "date_of_birth" => "", "course" => "", "sem" => "", "mobile_no" => "", "parent_mobile_no" => "", "email" => "", "password" => "", "confirm_password" => "", ]; public $validation_errors = []; public function emptyRegistrationForm(){ $this->user = [ "role" => "student", "first_name" => "", "last_name" => "", "date_of_birth" => "", "course" => "", "sem" => "", "mobile_no" => "", "parent_mobile_no" => "", "email" => "", "password" => "", "confirm_password" => "", ]; } public function save(){ $rules=[ 'role' => 'required', 'first_name' => 'required', 'last_name' => 'nullable', 'date_of_birth' => 'required|date', 'mobile_no' => 'required|integer', 'email' => 'required|email', 'password' => 'required', 'confirm_password' => 'required|same:password', ]; $messages = [ "role.required" => "Role must be selected", "first_name.required" => "First name must be filled", "date_of_birth.required" => "Date of Birth is required", "date_of_birth.date" => "Date of Birth must be in date format year/month/day", "mobile_no.required" => "Mobile number is required", "mobile_no.integer" => "Mobile number must be a number", "email.required" => "Email is required", "email.email" => "Invalid email id given.", "password.required" => "Password must be filled", "confirm_password.required" => "Confirm Password must be filled", "confirm_password.same" => "Confirm Password does not match Password", ]; if($this->user["role"]=="student"){ $rules = array_merge($rules, [ "course" => "required", "sem" => "required", "parent_mobile_no" => "required|integer", ]); $messages = array_merge($messages, [ "course.required" => "Course must be selected", "sem.required" => "Semester is required", "parent_mobile_no.required" => "Parent Mobile number is required", "parent_mobile_no.integer" => "Parent Mobile number must be a number", ]); } $validator_object = Validator::make($this->user,$rules, $messages); if($validator_object->fails()){ return $this->validation_errors = $validator_object->errors()->toArray(); }else{ //Create $info = [ "success" => FALSE, "user" => NULL, ]; DB::beginTransaction(); try { $query = [ "first_name" => $this->user["first_name"], "last_name" => $this->user["last_name"], "name" => $this->user["first_name"]." ".$this->user["last_name"], "email" => $this->user["email"], "password" => bcrypt($this->user["password"]), ]; // dd($query); $info["user"] = User::create($query); $query = [ "role" => $this->user["role"], "date_of_birth" => $this->user["date_of_birth"], "mobile_no" => $this->user["mobile_no"], "course" => $this->user["course"], "sem" => $this->user["sem"], "parent_mobile_no" => $this->user["parent_mobile_no"], ]; $info["user"]->profile()->create($query); DB::commit(); $info['success'] = TRUE; } catch (\Exception $e) { DB::rollback(); $info['success'] = FALSE; } } if($info["success"]){ $this->emptyRegistrationForm(); session()->flash('success', 'User registered successfully.'); }else{ session()->flash('error', 'Something went wrong while registration. Please try again later.'); } }
The public $user
is a class property which stores registration form data. I have made is as the array has it would be handling and lot to form information. During the save()
method validation rules and custom error messages are passed to Validator::make($this->user,$rules, $messages)
the rules are checked against $this->user
and if $validator_object->fails()
returns true (which means validation is failed) the errors are then assigned to $this->validation_errors
and displayed in the view.
It is recommended to use database transactions with a try-catch block if any errors occur while doing database operations.
The DB::commit()
the method will successfully store data into a database and if an exception occurs DB::rollback()
will automatically remove incorrect data from the database.
Registration form in resources/views/livewire/college-login-register/login-register.blade.php
.
<form class="col-md-12" wire:submit.prevent="save" method="post"> <div class="col-md-12"> <a href="javascript::void" wire:click="show('')" >Go back to Home Page</a> <h2 class="text-center" >Registration</h2> </div> <div class="col-md-12 role-choice-wrapper"> @if(session()->has('success')) <div class="alert alert-success alert-dismissible fade show"> <button type="button" class="close" data-dismiss="alert">×</button> {{ session('success') }} </div> @endif @if(session()->has('error')) <div class="alert alert-danger alert-dismissible fade show"> <button type="button" class="close" data-dismiss="alert">×</button> {{ session('error') }} </div> @endif <label for="">Select Role</label> <select class="form-control" wire:model="user.role"> <option value="teacher">Register as Teacher</option> <option value="student">Register as Student</option> </select> @if(isset($validation_errors["role"])) @foreach($validation_errors["role"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif <hr> </div> <div class="col-md-12 form-fields-container"> <div class="row"> <div class="col-md-6"> <label for="">First Name</label> <input type="text" class="form-control" wire:model="user.first_name" > @if(isset($validation_errors["first_name"])) @foreach($validation_errors["first_name"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">Last Name</label> <input type="text" class="form-control" wire:model="user.last_name" > </div> </div> <div class="row"> <div class="col-md-6"> <label for="">Email</label> <input type="text" class="form-control" wire:model="user.email" > @if(isset($validation_errors["email"])) @foreach($validation_errors["email"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">DOB</label> <input type="date" class="form-control" wire:model="user.date_of_birth" > @if(isset($validation_errors["date_of_birth"])) @foreach($validation_errors["date_of_birth"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> </div> @if($user["role"]=="student") <div class="row"> <div class="col-md-6"> <label for="">Course</label> <select class="form-control" wire:model="user.course" > <option value="">Choose one</option> <option value="mtech">M.Tech</option> <option value="be">BE</option> <option value="bca">BCA</option> <option value="bsc">BSc</option> </select> @if(isset($validation_errors["course"])) @foreach($validation_errors["course"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">Semester</label> <input type="text" class="form-control" wire:model="user.sem" > @if(isset($validation_errors["sem"])) @foreach($validation_errors["sem"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> </div> @endif <div class="row"> <div class="col-md-6"> <label for="">Parent Mobile No</label> <input type="text" class="form-control" wire:model="user.parent_mobile_no" > @if(isset($validation_errors["parent_mobile_no"])) @foreach($validation_errors["parent_mobile_no"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">Mobile No</label> <input type="text" class="form-control" wire:model="user.mobile_no" > @if(isset($validation_errors["mobile_no"])) @foreach($validation_errors["mobile_no"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> </div> <div class="row"> <div class="col-md-6"> <label for="">Password</label> <input type="password" class="form-control" wire:model="user.password" > @if(isset($validation_errors["password"])) @foreach($validation_errors["password"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">Confirm Password</label> <input type="password" class="form-control" wire:model="user.confirm_password" > @if(isset($validation_errors["confirm_password"])) @foreach($validation_errors["confirm_password"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> </div> </div> <div class="col-md-12"> <div class="form-group"> <input type="submit" class="btn btn-primary" value="Register" > </div> </div> </form>
Adding login functionalities to AuthComponent
I have added login and registration form in same view file that is resources/views/livewire/college-login-register/login-register.blade.php
.
Update the AuthComponent
with login functionality.
public $login = [ "email" => "", "password" => "", ]; public function verify(){ $rules=[ 'email' => 'required|email', 'password' => 'required', ]; $messages = [ "email.required" => "Email is required", "email.email" => "Invalid email id given.", "password.required" => "Password must be filled", ]; $validator_object = Validator::make($this->login,$rules, $messages); if($validator_object->fails()){ return $this->validation_errors = $validator_object->errors()->toArray(); }else{ //Create $user = User::where([ "email" => $this->login["email"], ])->get(); if(count($user)==1 && Hash::check($this->login["password"], $user[0]->password)){ session()->flash('success', "Yes! Login successful. You'r authenticated user"); }else{ session()->flash('error', 'You credentials does not match. Please try again later.'); } } }
The method verify()
will validate form and checks where user authenticated by displaying a success message.
The snippet for Login form in login-register.blade.php
.
<form wire:submit.prevent="verify" method="post"> <div class="row col-md-12"> <label for="">Email</label> <input type="text" class="form-control" wire:model="login.email" > @if(isset($validation_errors["email"])) @foreach($validation_errors["email"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="row col-md-12"> <label for="">Password</label> <input type="password" class="form-control" wire:model="login.password" > @if(isset($validation_errors["password"])) @foreach($validation_errors["password"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="row col-md-12"> <input type="submit" class="btn btn-success" value="Login" > </div> </form>
Navigating to Login and Registration Forms
Navigation and change UI as per client action as they can switch between login form or registration form.
public $wants_to_register = 0; public $wants_to_login = 0; public function show($mode){ if($mode=="register"){ $this->wants_to_register = 1; $this->wants_to_login = 0; }elseif($mode=="login"){ $this->wants_to_register = 0; $this->wants_to_login = 1; }else{ $this->wants_to_register = 0; $this->wants_to_login = 0; } }
The show($mode)
the method is responsible for displaying UI as per client actions.
@if($wants_to_register == 0 && $wants_to_login == 0) <div class="col-md-12 text-center" > <h2 class="text-center" >Laravel Livewire | Login & Registration Form</h2> <button type="button" class="btn btn-primary" wire:click="show('login')" >Login</button> <button type="button" class="btn btn-success" wire:click="show('register')" >Register</button> </div> @endif
In the end, your code must look like these below shown
AuthComponent
<?php namespace App\Http\Livewire\CollegeLoginRegister; use Livewire\Component; use Log; use Illuminate\Support\Facades\Validator; use App\User; use DB; use Illuminate\Support\Facades\Hash; class AuthComponent extends Component { public $user = [ "role" => "student", "first_name" => "", "last_name" => "", "date_of_birth" => "", "course" => "", "sem" => "", "mobile_no" => "", "parent_mobile_no" => "", "email" => "", "password" => "", "confirm_password" => "", ]; public $validation_errors = []; public $login = [ "email" => "", "password" => "", ]; public $wants_to_register = 0; public $wants_to_login = 0; public function mount(){ } public function show($mode){ if($mode=="register"){ $this->wants_to_register = 1; $this->wants_to_login = 0; }elseif($mode=="login"){ $this->wants_to_register = 0; $this->wants_to_login = 1; }else{ $this->wants_to_register = 0; $this->wants_to_login = 0; } } public function emptyRegistrationForm(){ $this->user = [ "role" => "student", "first_name" => "", "last_name" => "", "date_of_birth" => "", "course" => "", "sem" => "", "mobile_no" => "", "parent_mobile_no" => "", "email" => "", "password" => "", "confirm_password" => "", ]; } public function save(){ $rules=[ 'role' => 'required', 'first_name' => 'required', 'last_name' => 'nullable', 'date_of_birth' => 'required|date', 'mobile_no' => 'required|integer', 'email' => 'required|email', 'password' => 'required', 'confirm_password' => 'required|same:password', ]; $messages = [ "role.required" => "Role must be selected", "first_name.required" => "First name must be filled", "date_of_birth.required" => "Date of Birth is required", "date_of_birth.date" => "Date of Birth must be in date format year/month/day", "mobile_no.required" => "Mobile number is required", "mobile_no.integer" => "Mobile number must be a number", "email.required" => "Email is required", "email.email" => "Invalid email id given.", "password.required" => "Password must be filled", "confirm_password.required" => "Confirm Password must be filled", "confirm_password.same" => "Confirm Password does not match Password", ]; if($this->user["role"]=="student"){ $rules = array_merge($rules, [ "course" => "required", "sem" => "required", "parent_mobile_no" => "required|integer", ]); $messages = array_merge($messages, [ "course.required" => "Course must be selected", "sem.required" => "Semester is required", "parent_mobile_no.required" => "Parent Mobile number is required", "parent_mobile_no.integer" => "Parent Mobile number must be a number", ]); } $validator_object = Validator::make($this->user,$rules, $messages); if($validator_object->fails()){ return $this->validation_errors = $validator_object->errors()->toArray(); }else{ //Create $info = [ "success" => FALSE, "user" => NULL, ]; DB::beginTransaction(); try { $query = [ "first_name" => $this->user["first_name"], "last_name" => $this->user["last_name"], "name" => $this->user["first_name"]." ".$this->user["last_name"], "email" => $this->user["email"], "password" => bcrypt($this->user["password"]), ]; $info["user"] = User::create($query); $query = [ "role" => $this->user["role"], "date_of_birth" => $this->user["date_of_birth"], "mobile_no" => $this->user["mobile_no"], "course" => $this->user["course"], "sem" => $this->user["sem"], "parent_mobile_no" => $this->user["parent_mobile_no"], ]; $info["user"]->profile()->create($query); DB::commit(); $info['success'] = TRUE; } catch (\Exception $e) { DB::rollback(); $info['success'] = FALSE; } } if(!$info["success"]){ $this->emptyRegistrationForm(); session()->flash('success', 'User registered successfully.'); }else{ session()->flash('error', 'Something went wrong while registration. Please try again later.'); } } public function verify(){ $rules=[ 'email' => 'required|email', 'password' => 'required', ]; $messages = [ "email.required" => "Email is required", "email.email" => "Invalid email id given.", "password.required" => "Password must be filled", ]; $validator_object = Validator::make($this->login,$rules, $messages); if($validator_object->fails()){ return $this->validation_errors = $validator_object->errors()->toArray(); }else{ //Create $user = User::where([ "email" => $this->login["email"], ])->get(); if(count($user)==1 && Hash::check($this->login["password"], $user[0]->password)){ session()->flash('success', "Yes! Login successful. You'r authenticated user"); }else{ session()->flash('error', 'You credentials does not match. Please try again later.'); } } } public function render() { return view('livewire.college-login-register.login-register', []); } }
Login and Register View
<div id="auth-container" > <style> label{ color: #000000; } #auth-container{ background: #999; padding: 15px 0; height: 100vh; } #auth-container > .wrapper{ width: 40%; background: #fff; margin: auto; padding: 15px 10px; } .form-fields-container .row{ margin-bottom: 25px; } </style> <div class="row wrapper"> @if($wants_to_register == 0 && $wants_to_login == 0) <div class="col-md-12 text-center" > <h2 class="text-center" >Laravel Livewire | Login & Registration Form</h2> <button type="button" class="btn btn-primary" wire:click="show('login')" >Login</button> <button type="button" class="btn btn-success" wire:click="show('register')" >Register</button> </div> @else @if($wants_to_login) <div class="col-md-12"> <a href="javascript::void" wire:click="show('')" >Go back to Home Page</a> <h2 class="text-center" >Login</h2> </div> <div class="col-md-12 role-choice-wrapper"> @if(session()->has('success')) <div class="alert alert-success alert-dismissible fade show"> <button type="button" class="close" data-dismiss="alert">×</button> {{ session('success') }} </div> @endif @if(session()->has('error')) <div class="alert alert-danger alert-dismissible fade show"> <button type="button" class="close" data-dismiss="alert">×</button> {{ session('error') }} </div> @endif </div> <div class="col-md-12 form-fields-container"> <form wire:submit.prevent="verify" method="post"> <div class="row col-md-12"> <label for="">Email</label> <input type="text" class="form-control" wire:model="login.email" > @if(isset($validation_errors["email"])) @foreach($validation_errors["email"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="row col-md-12"> <label for="">Password</label> <input type="password" class="form-control" wire:model="login.password" > @if(isset($validation_errors["password"])) @foreach($validation_errors["password"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="row col-md-12"> <input type="submit" class="btn btn-success" value="Login" > </div> </form> </div> @endif @if($wants_to_register) <form class="col-md-12" wire:submit.prevent="save" method="post"> <div class="col-md-12"> <a href="javascript::void" wire:click="show('')" >Go back to Home Page</a> <h2 class="text-center" >Registration</h2> </div> <div class="col-md-12 role-choice-wrapper"> @if(session()->has('success')) <div class="alert alert-success alert-dismissible fade show"> <button type="button" class="close" data-dismiss="alert">×</button> {{ session('success') }} </div> @endif @if(session()->has('error')) <div class="alert alert-danger alert-dismissible fade show"> <button type="button" class="close" data-dismiss="alert">×</button> {{ session('error') }} </div> @endif <label for="">Select Role</label> <select class="form-control" wire:model="user.role"> <option value="teacher">Register as Teacher</option> <option value="student">Register as Student</option> </select> @if(isset($validation_errors["role"])) @foreach($validation_errors["role"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif <hr> </div> <div class="col-md-12 form-fields-container"> <div class="row"> <div class="col-md-6"> <label for="">First Name</label> <input type="text" class="form-control" wire:model="user.first_name" > @if(isset($validation_errors["first_name"])) @foreach($validation_errors["first_name"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">Last Name</label> <input type="text" class="form-control" wire:model="user.last_name" > </div> </div> <div class="row"> <div class="col-md-6"> <label for="">Email</label> <input type="text" class="form-control" wire:model="user.email" > @if(isset($validation_errors["email"])) @foreach($validation_errors["email"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">DOB</label> <input type="date" class="form-control" wire:model="user.date_of_birth" > @if(isset($validation_errors["date_of_birth"])) @foreach($validation_errors["date_of_birth"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> </div> @if($user["role"]=="student") <div class="row"> <div class="col-md-6"> <label for="">Course</label> <select class="form-control" wire:model="user.course" > <option value="">Choose one</option> <option value="mtech">M.Tech</option> <option value="be">BE</option> <option value="bca">BCA</option> <option value="bsc">BSc</option> </select> @if(isset($validation_errors["course"])) @foreach($validation_errors["course"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">Semester</label> <input type="text" class="form-control" wire:model="user.sem" > @if(isset($validation_errors["sem"])) @foreach($validation_errors["sem"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> </div> @endif <div class="row"> <div class="col-md-6"> <label for="">Parent Mobile No</label> <input type="text" class="form-control" wire:model="user.parent_mobile_no" > @if(isset($validation_errors["parent_mobile_no"])) @foreach($validation_errors["parent_mobile_no"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">Mobile No</label> <input type="text" class="form-control" wire:model="user.mobile_no" > @if(isset($validation_errors["mobile_no"])) @foreach($validation_errors["mobile_no"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> </div> <div class="row"> <div class="col-md-6"> <label for="">Password</label> <input type="password" class="form-control" wire:model="user.password" > @if(isset($validation_errors["password"])) @foreach($validation_errors["password"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> <div class="col-md-6"> <label for="">Confirm Password</label> <input type="password" class="form-control" wire:model="user.confirm_password" > @if(isset($validation_errors["confirm_password"])) @foreach($validation_errors["confirm_password"] as $k => $v) <label for="" class="error">{{ $v }}</label> @endforeach @endif </div> </div> </div> <div class="col-md-12"> <div class="form-group"> <input type="submit" class="btn btn-primary" value="Register" > </div> </div> </form> @endif @endif </div> </div>
Web Routes
// Livewire College login and registration routes Route::get('college', function(){ return view('livewire.college-login-register.base', []); });
Base View
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Laravel LiveWire Login & Register Application</title> @livewireStyles <link rel="stylesheet" href="{{ url('assets/css/bootstrap.min.css') }}"> <style> .error{ color: red; } </style> </head> <body> @livewire('college-login-register.auth-component') <!-- {# livewire('CollegeLoginRegister.Registers') #} this does not work --> @livewireScripts <script src="{{ url('assets/js/jquery.min.js') }}"></script> <script src="{{ url('assets/js/popper.min.js') }}"></script> <script src="{{ url('assets/js/bootstrap.min.js') }}"></script> </body> </html>
Final Output
Registration Form
Login Form
View Output on Video
You have come to end of this tutorial on Laravel Livewire | Login & Dynamic Registration Form for Multiple Roles for the suggestion you can contact us by going to our contact page and sharing this article will definitely help us grow.