Monday, December 13, 2021

Laravel 8 Livewire Wizard Form Tutorial with Example

Generate Laravel Project

The first step begins with creating a new laravel application using the composer command:

composer create-project laravel/laravel --prefer-dist laravel-multistep-form-example

Bash

Connect with Database

Afterwards, you need to add database name, username equally important password in .env configuration file:


DB_CONNECTION=mysql

DB_HOST=127.0.0.1

DB_PORT=3306

DB_DATABASE=database_name

DB_USERNAME=root

DB_PASSWORD=

.properties

Model and Migration

Use command to manifest laravel model by the same token migration files:


php artisan make:model Team -m

Bash

Define table values in database/migrations/create_teams_table.php file:


<?php


use Illuminate\Database\Migrations\Migration;

use Illuminate\Database\Schema\Blueprint;

use Illuminate\Support\Facades\Schema;


class CreateTeamsTable extends Migration

{

    /**

     * Run the migrations.

     *

     * @return void

     */

    public function up()

    {

        Schema::create('teams', function (Blueprint $table) {

            $table->id();

            $table->string('name')->nullable();

            $table->float('price')->nullable();

            $table->longText('detail')->nullable();

            $table->boolean('status')->default(0);        

            $table->timestamps();

        });

    }


    /**

     * Reverse the migrations.

     *

     * @return void

     */

    public function down()

    {

        Schema::dropIfExists('teams');

    }

}

PHP

Add the following code in the app/Models/Team.php file:


<?php


namespace App\Models;


use Illuminate\Database\Eloquent\Factories\HasFactory;

use Illuminate\Database\Eloquent\Model;


class Team extends Model

{

    use HasFactory;

    protected $fillable = [

        'name', 

        'price', 

        'detail', 

        'status'

    ];    

}

PHP

Run migration with following command:


php artisan migrate

Bash

Install Livewire Package

Now that, you have to use the following command to install the livewire package in your laravel application:


composer require livewire/livewire

Bash

Create Livewire Component

Go to console run the artisan command to create the livewire components:


php artisan make:livewire wizard

Bash

The above command generated two files on the following path:


app/Http/Livewire/Wizard.php

resources/views/livewire/wizard.php

.properties

Go ahead and place the below code in the app/Http/Livewire/Wizard.php file:


<?php

  

namespace App\Http\Livewire;

use Livewire\Component;

use App\Models\Team;

  

class Wizard extends Component

{

    public $currentStep = 1;

    public $name, $price, $detail, $status = 1;

    public $successMsg = '';

  

    /**

     * Write code on Method

     */

    public function render()

    {

        return view('livewire.wizard');

    }

  

    /**

     * Write code on Method

     */

    public function firstStepSubmit()

    {

        $validatedData = $this->validate([

            'name' => 'required',

            'price' => 'required|numeric',

            'detail' => 'required',

        ]);

 

        $this->currentStep = 2;

    }

  

    /**

     * Write code on Method

     */

    public function secondStepSubmit()

    {

        $validatedData = $this->validate([

            'status' => 'required',

        ]);

  

        $this->currentStep = 3;

    }

  

    /**

     * Write code on Method

     */

    public function submitForm()

    {

        Team::create([

            'name' => $this->name,

            'price' => $this->price,

            'detail' => $this->detail,

            'status' => $this->status,

        ]);

  

        $this->successMsg = 'Team successfully created.';

  

        $this->clearForm();

  

        $this->currentStep = 1;

    }

  

    /**

     * Write code on Method

     */

    public function back($step)

    {

        $this->currentStep = $step;    

    }

  

    /**

     * Write code on Method

     */

    public function clearForm()

    {

        $this->name = '';

        $this->price = '';

        $this->detail = '';

        $this->status = 1;

    }

}

PHP

Next, open resources/views/livewire/wizard.blade.php file, add the following code:


<div>

    @if(!empty($successMsg))

    <div class="alert alert-success">

        {{ $successMsg }}

    </div>

    @endif

    <div class="stepwizard">

        <div class="stepwizard-row setup-panel">

            <div class="multi-wizard-step">

                <a href="#step-1" type="button"

                    class="btn {{ $currentStep != 1 ? 'btn-default' : 'btn-primary' }}">1</a>

                <p>Step 1</p>

            </div>

            <div class="multi-wizard-step">

                <a href="#step-2" type="button"

                    class="btn {{ $currentStep != 2 ? 'btn-default' : 'btn-primary' }}">2</a>

                <p>Step 2</p>

            </div>

            <div class="multi-wizard-step">

                <a href="#step-3" type="button"

                    class="btn {{ $currentStep != 3 ? 'btn-default' : 'btn-primary' }}"

                    disabled="disabled">3</a>

                <p>Step 3</p>

            </div>

        </div>

    </div>

    <div class="row setup-content {{ $currentStep != 1 ? 'display-none' : '' }}" id="step-1">

        <div class="col-md-12">

            <h3> Step 1</h3>

            <div class="form-group">

                <label for="title">Team Name:</label>

                <input type="text" wire:model="name" class="form-control" id="taskTitle">

                @error('name') <span class="error">{{ $message }}</span> @enderror

            </div>

            <div class="form-group">

                <label for="description">Team Price:</label>

                <input type="text" wire:model="price" class="form-control" id="teamPrice" />

                @error('price') <span class="error">{{ $message }}</span> @enderror

            </div>

            <div class="form-group">

                <label for="detail">Team Details:</label>

                <textarea type="text" wire:model="detail" class="form-control"

                    id="taskDetail">{{{ $detail ?? '' }}}</textarea>

                @error('detail') <span class="error">{{ $message }}</span> @enderror

            </div>

            <button class="btn btn-primary nextBtn btn-lg pull-right" wire:click="firstStepSubmit"

                type="button">Next</button>

        </div>

    </div>

    <div class="row setup-content {{ $currentStep != 2 ? 'display-none' : '' }}" id="step-2">

        <div class="col-md-12">

            <h3> Step 2</h3>

            <div class="form-group">

                <label for="description">Team Status</label><br />

                <label class="radio-inline"><input type="radio" wire:model="status" value="1"

                        {{{ $status == '1' ? "checked" : "" }}}> Active</label>

                <label class="radio-inline"><input type="radio" wire:model="status" value="0"

                        {{{ $status == '0' ? "checked" : "" }}}> DeActive</label>

                @error('status') <span class="error">{{ $message }}</span> @enderror

            </div>

            <button class="btn btn-primary nextBtn btn-lg pull-right" type="button"

                wire:click="secondStepSubmit">Next</button>

            <button class="btn btn-danger nextBtn btn-lg pull-right" type="button" wire:click="back(1)">Back</button>

        </div>

    </div>

    <div class="row setup-content {{ $currentStep != 3 ? 'display-none' : '' }}" id="step-3">

        <div class="col-md-12">

            <h3> Step 3</h3>

            <table class="table">

                <tr>

                    <td>Team Name:</td>

                    <td><strong>{{$name}}</strong></td>

                </tr>

                <tr>

                    <td>Team Price:</td>

                    <td><strong>{{$price}}</strong></td>

                </tr>

                <tr>

                    <td>Team status:</td>

                    <td><strong>{{$status ? 'Active' : 'DeActive'}}</strong></td>

                </tr>

                <tr>

                    <td>Team Detail:</td>

                    <td><strong>{{$detail}}</strong></td>

                </tr>

            </table>

            <button class="btn btn-success btn-lg pull-right" wire:click="submitForm" type="button">Finish!</button>

            <button class="btn btn-danger nextBtn btn-lg pull-right" type="button" wire:click="back(2)">Back</button>

        </div>

    </div>

</div>

PHP

Next, add custom styling in multi-step form. So create a public/multiform.css file and add the following code:


.display-none {

    display: none;

}


.multi-wizard-step p {

    margin-top: 12px;

}


.stepwizard-row {

    display: table-row;

}


.stepwizard {

    display: table;

    position: relative;

    width: 100%;

}


.multi-wizard-step button[disabled] {

    filter: alpha(opacity=100) !important;

    opacity: 1 !important;

}


.stepwizard-row:before {

    top: 14px;

    bottom: 0;

    content: " ";

    width: 100%;

    height: 1px;

    z-order: 0;

    position: absolute;

    background-color: #fefefe;

}


.multi-wizard-step {

    text-align: center;

    position: relative;

    display: table-cell;

}

CSS

Create Form Route

Open routes/web.php file and define the route to access the multistep form from view:


<?php


use Illuminate\Support\Facades\Route;


/*

|--------------------------------------------------------------------------

| Web Routes

|--------------------------------------------------------------------------

|

*/


Route::get('wizard', function () {

    return view('welcome');

});

PHP

Render Multi-step Form in Blade View

Add below code in resources/views/welcome.blade.php file:


<!DOCTYPE html>

<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">


<head>

    <meta charset="utf-8">

    <meta name="viewport" content="width=device-width, initial-scale=1">

    <title>Laravel Multistep Livewire Form Example</title>

    @livewireStyles


    <link href="//maxcdn.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" rel="stylesheet" id="bootstrap">

    <link href="{{ asset('multiform.css') }}" rel="stylesheet" id="bootstrap">

</head>


<body class="mt-5">

    <div class="container">

        <div class="text-center">

            Laravel Form Wizard Example

        </div>

        <livewire:wizard />

    </div>

</body>


<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>

<script src="//maxcdn.bootstrapcdn.com/bootstrap/4.1.1/js/bootstrap.min.js"></script>

@livewireScripts


</html>

PHP

Now you can run the app to check the multi-step form.


php artisan serve

Bash

Open the URL on the browser:


http://localhost:8000/wizard


https://www.positronx.io/laravel-livewire-wizard-form-tutorial-with-example/




Preparing Google Maps API

 

This is probably the step that most tutorials will be skipping, because it’s not about the code. It’s about access to Google Maps API. To use it, you need to create an application in Google Developer Console and enable a bunch of APIs related to Maps.

Not only that, in June 2018 Google changed Maps API usage and pricing. Basically, you can’t use Google API without enabling billing in Google Developer Console. In other words, you need to put your credit card there.

At this moment of writing (January 2019), there’s $200 per month of free credit, but as soon as you reach it, the price is pretty heavy. Here’s a graph from one of my client’s project – we reached free credit limit on 13th of the month, and from there it only depends on how many visitors you have who open a page with the map.

And this was the invoice – for roughly 40,000 visitors per month:

So, my overall warning to you:

  • You need to put your Credit Card to use Google Maps API
  • But be extremely careful with maps usage cause you may get a huge bill

Now, if you’re ready to proceed – you need to get Google Maps API key, and this is the page to start.

So you need to create an Application in Google Console, and enable some APIs. To achieve the example in this article, you need three APIs, here’s the list from my dashboard.

Look at only those with numbers. You need:

  • Maps JavaScript API: to show embedded map on the page
  • Places API for Web: to provide auto-complete functionality for address
  • Geocoding API: to query the latitude/longitude by the address

Now, in this process you should get your API key, which will be the key to all of this. We put it in our Laravel project’s .env file:

GOOGLE_MAPS_API_KEY=AIzaSyBi2dVBkdQSUcV8_uwwa**************

Warning again: As I mentioned, be extremely careful and not put that anywhere in the repository, cause you may get a bill for someone else’s project. Or, better yet, restrict your API key by domain or some other method.

Now, we are ready to actually USE those maps!