Validation server-side and client-side in Laravel6.0 (bootstrap4 + jquery validate) in I went memo

Overview

The last time it was confirmed that it is creating a list.

This time, was also front of validation using the bootstrap4 and jquery validation.

Installation of Form for library

It was introduced into the library to be easier to handle the Form in the blade.

composer require laravelcollective/html
 

Validation in Laravel

Creating a migration file

Create a model to create a master of the table to be created this time.

<?php
 use Illuminate\Database\Migrations\Migration;
 use Illuminate\Database\Schema\Blueprint;
 use Illuminate\Support\Facades\Schema;

class CreateCouponsTable extends Migration {
public function up()
{
Schema::create('coupons', function (Blueprint $table) {
$table->string('id');
$table->integer('type')->default(config('const.Coupons.TYPE_GET', 1))->comment('1: acquisition, 2: using' );
$table->string('name');
$table->integer('point')->default(0);
$table->boolean('is_display')->default(true);
$table->timestamp('created_at')->useCurrent();
$table->timestamp('updated_at')->default(DB::raw('CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP'));

$table->primary('id');
});
}

public function down()
{
Schema::dropIfExists('coupons');
} }

Creating a model

If you do not do the settings for the following main key, it becomes zero when displaying the string type of id in HTML.

app/Models/Coupon.php
<?php
 namespace App\Models;
 use Illuminate\Database\Eloquent\Model;

class Coupon extends Model {
protected $keyType = 'string';
public $incrementing = false; }

Configuring Routing

routes/web.php
    Route::put('/tag/{tag}','Admin\TagController@update');

+ Route::get('/coupon','Admin\CouponController@index');
+ Route::post('/coupon','Admin\CouponController@store');
+ Route::put('/coupon/{coupon}','Admin\CouponController@update');
+ Route::delete('/coupon/{coupon}','Admin\CouponController@destroy');

Controller Settings

It is doing a set of pagination in the index.

It is doing when you create a validation of the server side in the store.

Since id is key, it has been confirmed that it is unique.

The above validation in the update is not required.

Since the null when data checkbox is not checked,

and to store the bool value DB performed compared to the value when there is a check.

app/Http/Controllers/Admin/CouponController.php
<?php
 namespace App\Http\Controllers\Admin;
 use App\Http\Controllers\Controller;
 use App\Models\Coupon;
 use Illuminate\Http\Request;

class CouponController extends Controller {
public function index()
{
$coupons = Coupon::orderBy('updated_at', 'DESC')->paginate(config('const.Paginator.PER_PAGE'));
return view('admin/coupons', [
'coupons' => $coupons,
'types' => [ config('const.Coupons.TYPE_GET', 1) => 'Get' ,
config('const.Coupons.TYPE_USE', 2) => 'used' ]
]);
}

public function store(Request $request)
{
//Bail: If you fail the first validation, stop the judgment of the rest of the validation rules
$validatedData = $request->validate([
'id' => 'bail|required|unique:coupons|max:255',
'name' => 'bail|required|max:255',
'point' => 'required|integer',
'type' => 'required|integer'
]);

$coupon = new Coupon();
$coupon->id = $request->id;
$coupon->name = $request->name;
$coupon->point = $request->point;
$coupon->type = $request->type;
$coupon->is_display = $request->is_display === '1';
$coupon->save();

return redirect('/coupon');
}

public function update(Request $request, Coupon $coupon)
{
$validatedData = $request->validate([
'name' => 'bail|required|max:255',
'point' => 'required|integer',
'type' => 'required|integer'
]);

$coupon->name = $request->name;
$coupon->point = $request->point;
$coupon->type = $request->type;
$coupon->is_display = $request->is_display === '1';
$coupon->save();

return redirect('/coupon');
}
public function destroy(Coupon $coupon)
{
$coupon->delete();

return redirect('/coupon');
} }

View

Hide because long

resources/views/admin/coupon.blade.php
@extends('layouts.app')
 @section('title') coupon management  @endsection
 @section('admin')

<li class="nav-item"><a class="nav-link" href="{{ url('/admin') }}">administrator dashboard </span></a></li> @endsection

@section('content')
<div id="editModal" class="modal fade" tabindex="-1" role="dialog">
<form id="edit-form" action="dummy{{--Js in replacement -} }" method="POST">
@csrf
@method('PUT')
<div class="modal-dialog" role="document"><divclass=
"modal-content"> <divclass=
"modal-header"> <h5class=
"modal-title"> Class </h5><buttontype=
"button"class ="close"data -dismiss= "modal"aria-label= Aria ><spanaria-
hidden= "true">&times;</span>
</button>
</div>{{-- /.modal-header --}}
<div class="modal-body">
{{-- Coupons name --}}
<div class="form-group row">
<label for="edit-coupon-name" class="col-sm-3 col-form-label">coupon name </label>

<div class="col-sm-6">
<input type="text" name="name" id="edit-coupon-name" class="form-control" value="{{ old('coupon') }}" required>
<div class="valid-feedback">
already entered !
</div>
</div>
</div>
{{-- Coupon Species --}}
<div class="form-group row">
<label for="edit-coupon-type" class="col-sm-3 col-form-label">coupon type </label>

<div class="col-sm-6">
{{Form::select('type', $types, old('coupon')) }}
</div>
</div>
{{-- Coupon value --}}
<div class="form-group row">
<label for="edit-coupon-point" class="col-sm-3 col-form-label">value </label>

<div class="col-sm-6"> <inputtype="number"name="point"id="edit-coupon-point"class=
"form-control"value ="{{ old('coupon', 0) }}"required ></div ></div >{{-- Value --}} <div
class="form-group row form-check"
><div
class= "col-sm-6" >{{
Form:: checkbox('is_display',
true, true,['class'
=> 'form-check-input' ,'id' =>'edit-coupon-is_display' ])}} <label for="edit-coupon-is_display"class
="form-check-label" >= </ label></div></div>
</div>
{{--/.
modal-body--}} <divclass= "modal-footer">
<
button type="button" class="btn btn-secondary" data-dismiss="modal">Close </button>
<button type="submit" class="btn btn-primary">Save changes </button>
</div>{{-- /.modal-footer --}}
</div>{{-- /.modal-content --}}
</div>{{-- /.modal-dialog --}}
</form>
</div>{{-- /.modal --}}

{{-- Delete modal --}}
<div id="deleteModal"class="modal fade"tabindex="-1"role="dialog"><formid="delete-form"action="dummy"method="POST">@csrf@method('DELETE')<divclass="modal-dialog" role="document" ><div class="modal-content">
<div class="modal-header" ><h5 class="modal-title">
Atto </
h5><buttontype
="button" class="close" data-dismiss=
"modal"aria
-
label= Class ><spanaria-hidden=
"true">& times;</ span></ button></div> {{--/.modal-header
--}} <divclass="modal-body"><markid=

"delete-item-name"
>{{ --= --}}
</mark >= "delete-item The-name" > {{ </ div >{{--/.modal-body--}}
<divclass="modal-footer" ><buttontype ="button"
class= "btn btn-secondary"
data-dismiss="modal">Close </button>
<button type="submit" class="btn btn-danger">delete </button>
</div>{{-- /.modal-footer --}}
</div>{{-- /.modal-content --}}
</div>{{-- /.modal-dialog --}}
</form>
</div>{{-- /.modal --}}

{{-- Main here --}}
<main class="container">
<div class="col-sm-offset-2 col-sm-8">
<div class="card">
<div class="card-header">new coupon </div>
<div class="card-body">
{{-- display of validation error --}}
@include('common.errors')

{{-- new coupon form --}}
<form id="create-form" action="{{ url('coupon')}}" method="POST">
@csrf
{{-- coupon ID --}}
<div class="form-group row">
<label for="coupon-id" class="col-sm-3 col-form-label" >coupon ID </label>

<div class="col-sm-6">
<input type="text" name="id" id="coupon-id" class="form-control" aria-describedby="idHelpBlock" value="{{ old('coupon') }}" required>
<small id="idHelpBlock" class="form-text text-muted">ID is alphanumeric characters and -_ a , please enter the ones that do not overlap </small>
</div>
</div>

{{-- coupon name --}}
<div class="form-group row">
<label for="coupon-name" class="col-sm-3 col-form-label">coupon name </label>

<div class="col-sm-6">
<input type="text" name="name" id="coupon-name" class="form-control" value="{{ old('coupon') }}" required>
<div class="valid-feedback">
already entered !
</div>
</div>
</div>
{{-- Coupon Species --}}
<div class="form-group row">
<label for="coupon-type" class="col-sm-3 col-form-label">coupon type </label>

<div class="col-sm-6">
{{Form::select('type', $types, old('coupon')) }}
</div>
</div>
{{-- Coupon value --}}
<div class="form-group row">
<label for="coupon-point" class="col-sm-3 col-form-label">value </label>

<div class="col-sm-6">
<input type="number" name="point" id="coupon-point" class="form-control" value="{{ old('coupon', 0) }}" required>
</div>
</div>
{{-- display flag --}}
<div class="form-group row form-check">
<div class="col-sm-6">

{{Form::checkbox('is_display', true, true, ['class' => 'form-check-input', 'id'=>'coupon-is_display'])}}
<label for="coupon-is_display" class="form-check-label">display </label>
</div>
</div>
{{-- coupon add button --}}
<div class="form-group row">
<div class="col-sm-offset-3 col-sm-6">
<button type="submit" class="btn btn-primary">
<i class="fa fa-btn fa-plus"></i> coupon add
</button>
</div>
</div>
</form>
</div>
</div>

@if (count($coupons) > 0)
<div class="card">
<div class="card-header">Coupon List </div>
<div class="card-body">
<table class="table table-striped coupon-table">
{{-- tableHeader --}}
<thead>
<tr>
<th>ID</th>
<th>coupon </th>
<th>value </th>
<th>type </th>
<th>- </th><th></</th
><th>{{-->
--}}&nbsp; </ th><th>{{-->
--}}&nbsp; </th>
</tr>
</thead>
{{-- table body --}}
<tbody>
@foreach ($coupons as$coupon)<tr><tdclass="table-text"><div>{{$coupon->id}}</div></td><tdclass="table-text"><div >{{
$coupon->name
}}</ div></td
><tdclass ="table-text"> <div>{{
$coupon->point
}}</



div></ td>< tdclass="table-text"
><div
>{{ $types[$coupon->
type]}}</ div></td><

td class="table-text">
<div>{{ $coupon->is_display ? 'Display' : 'hide' }}</div>
</td>
<td class="table-text">
<div>{{ $coupon->updated_at->format('Y/m/d H:i:s') }}</div>
</td>
<td>
<button type="button" class="btn" data-toggle="modal" data-target="#editModal"
data-action="{{ url('coupon/' . $coupon->id) }}" data-name="{{$coupon->name}}" data-point="{{$coupon->point}}"
data-is_display="{{$coupon->is_display}}" data-type="{{$coupon->type}}"
>
<i class="fa fa-btn fa-edit"></i>
</button>
</td>
<td>
<button type="button" class="btn btn-danger" data-toggle="modal" data-target="#deleteModal"
data-action="{{ url('coupon/' . $coupon->id) }}" data-name="{{$coupon->name}}"
>
<i class="fa fa-btn fa-trash"></i>
</button>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
</div>
@endif
{{ $coupons->links() }}
</div>
</div> @endsection

@section('scripts') <script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.1/dist/jquery.validate.min.js" integrity="sha256-sPB0F50YUDK0otDnsfNHawYmA5M0pjjUf4TvRJkGFrI=" crossorigin="anonymous"></script> <script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.1/dist/additional-methods.min.js"></script> <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.19.1/localization/messages_ja.js"></script> <script src="{{ mix('js/admin/coupon/index.js') }}"></script> @endsection

Not doing last time, how much you have put the tag for paging.

            @endif
 +            {{ $coupons->links() }}
         </div>

</div> @endsection

The client-side validation

Additional libraries

Append the following line at the view.

This time do a unique check in the remote of jquery-validation, we are the ones that are not slim the jquery.
TypeError: undefined is not an object (evaluating 'b.apply'). Exception occurred when checking element , check the 'remote' method.Error such as would come out that it is slim.

In addition, since the check of a regular expression in the pattern, it is also added additional-methods library.

resouces/views/admin/coupon.blade.php
 @section('scripts')
 <script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.1/dist/jquery.validate.min.js" integrity="sha256-sPB0F50YUDK0otDnsfNHawYmA5M0pjjUf4TvRJkGFrI=" crossorigin="anonymous"></script>
 <script src="https://cdn.jsdelivr.net/npm/jquery-validation@1.19.1/dist/additional-methods.min.js"></script>
 <script src="https://ajax.aspnetcdn.com/ajax/jquery.validate/1.19.1/localization/messages_ja.js"></script>
 <script src="{{ mix('js/admin/coupon/index.js') }}"></script>
 @endsection
 

Transformer pile set

webpack.mix.js
+ mix.ts('resources/ts/admin/coupon/index.ts', 'public/js/admin/coupon').version();
 

Additional settings for the typescript

@types/jquery.validationVersion has stopped at 1.16, do not use for up-to-date was 1.19.

It was carried out the following settings in order to pass the compilation.

tsconfig.json
{

"compilerOptions": {
"outDir": "./built/",

//omitted

+ "typeRoots": ["./resources/ts/types", "node_modules/@types"] },

"include": ["resources/ts/**/*"] }

resouces/ts/types/index.d.ts
interface JQuery {

validate(options: any): JQuery; } interface JQueryStatic {
validator: any; }

Set of validation

During the verification failure/success, and to set the class of bootstrap4.

resources/ts/admin/coupon/index.ts
import { ModalEventHandler } from 'bootstrap';

$.validator.setDefaults({
debug: false, the case of//true, form enters debug mode is not sent
onkeyup: false, //for the case of a valid will run the remote every time Keyup ..
success: null,
validClass: 'valid-feedback',
errorClass: 'invalid-feedback',
errorElement: 'span',
errorPlacement: function(error: JQuery, element: JQuery) {
error.addClass('invalid-feedback');
element.closest('.form-group').append(error);
},
highlight: function(element: HTMLElement, errorClass: string, validClass: string) {
$(element).addClass('is-invalid');
},
unhighlight: function(element: HTMLElement, errorClass: string, validClass: string) {
$(element).removeClass('is-invalid');
} }); const $createForm: JQuery<HTMLFormElement> = $('#create-form'); $createForm
.submit(event => {
//custom validation Bootstrap4
const form = event.target;
if (form.checkValidity() === false) {
event.preventDefault();
event.stopPropagation();
}
form.classList.add('was-validated');
})
.validate({
rules: {
id: {
required: true,
remote: '/api/coupon/unique',
pattern: '[a-zA-Z0-9_-]+' a//pattern reading of additonal to use is necessary
},
name: { required: true },
point: { required: true, number: true }
},
messages: { id:
{remote :
': ',pattern:
'You can use the alphanumeric and -_ '
}
}
});

//EDIT $('#editModal').on('show.bs.modal', function(event: ModalEventHandler<HTMLElement>) {
const target = event.relatedTarget;
if (target === undefined) {
return;
}
const $button=$(target);Action constaction= $button .data(' action
' ); //extract the information from the data- * attribute
const name = $button.data('name');
const point = $button.data('point');
const type = $button.data('type');
const is_display = $button.data('is_display') === 1;

const $modal = $(this);
$modal.find('#edit-coupon-name').val(name);
$modal.find('#edit-coupon-type').val(type);
$modal.find('#edit-coupon-point').val(point);
$modal.find('#edit-coupon-is_display').prop('checked', is_display);
$modal.find('#edit-form').attr('action', action); });

//customize the HTML5 standard of error messages $('#edit-coupon-name').on('invalid', e => {
const nameInput = e.target as HTMLInputElement;
if (nameInput.value === '') {
nameInput.setCustomValidity(' Please enter a name. ');
} });

//delete $('#deleteModal').on('show.bs.modal', function(event: ModalEventHandler<HTMLElement>) {
const target = event.relatedTarget;
if (target === undefined) {
return;
}
const $button = $(target);( constaction=$button.data( '
action ' ); //Data- * attribute extract information from
const name = $button.data('name');

const $modal = $(this);
$modal.find('#delete-item-name').text(name);
$modal.find('#delete-form').attr('action', action); });

Check on the server side

called in the remote of jquery.validate, create an API that returns a true/false.

So that kiss false if it fails to validation.

Routing configuration

routes/api.php
+ Route::get('/coupon/unique','Actions\CouponAction@unique');
 

controller

app/Http/Controllers/Actions/CouponAction.php
<?php
 namespace App\Http\Controllers\Actions;
 use App\Http\Controllers\Controller;
 use App\Models\Coupon;
 use Illuminate\Http\Request;

class CouponAction extends Controller {
/**
* True if they do not exist. If it exists return a False
*/

public function unique(Request $request)
{
$result = true;
if ($request->has('id')) {
$result = ! Coupon::where('id', '=', $request->query('id'))->exists();
}
return response()->json($result);
} }

Source of so far

reference

Laravel 6.0 validation
jQuery Validation
JQuery Validation Plugin is easy to use and recommend
jsdelivr
Laravel 6.0 Blade template
to introduce a TypeScript to the front-end of Laravel
the Vue.js of Laravel mix going to the TypeScript
jquery-validation
of the [Laravel] Model save Then, the there is that the id of the instance becomes 0
'Bootsrap 4.0.0 stable' causes 'Uncaught TypeError: Cannot read property 'apply' of undefined.'
verification of the value of communicating to the jQuery validation server (Remote)
Jquery.Validate. addictive error message display control of js
use the jQuery validation in combination with Bootstrap Twitter
validate and bootstrap4
to realize the validation of the password match the front-end completed in BootStrap4
the novalidate to grant. html5 validation and validate can not be used at the same time.
It could have been because of the options.success jquery validation of Submit Gadoerai slow in the page where there is a large number of Input tag.
Cooperation with jQuery Validate Plugin commentary and Validate Japanese environment for Plugin and JQuery Form Plugin
mdn:input
to create a check box
php:date
when using the jQuery Validation Plugin, to enable the button when the form is made to verified to
LaravelCollective Form facade cheat sheet