11
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

jQueryのajaxを使って非同期通信を導入したい

Posted at

今参加しているプログラミングスクールでの課題で、LaravelでECsiteを作っているのですが、ユーザー情報を登録する際に、validationを非同期通信で行ったら便利そうということで導入します

作りたいもの

  • ECsite(の一部)
  • ユーザー情報登録画面で未入力等の項目があった場合にvalidationで弾く
  • そのvalidationを非同期で行う(エラーが出たら画面遷移をせずにエラー文を表示)
  • エラーがなかったら、入力内容確認画面へ自動遷移

非同期通信とは?

以下の記事がとてもわかりやすかったです。
初心者目線でAjaxの説明

なんとなくわかった気にはなった...

何を使う?

jQueryのajax関数を使うのが簡単でいいらしいです
はじめてのAjax(jQuery) 2018年版

早速作成

まずはひな形を作成

フォームの作り方は省略で、以下のものができているとします

user_regist.blade.php
@extends('common.layout')

@section('title')
    ユーザー新規登録
@endsection

@section('header')
@endsection

@section('bodyTitle')
    <h2>新規登録画面</h2>
@endsection

@section('body')
    <form action="user_confirm" method="post" id="form">
    @csrf
        名前必須):<br />
        <input type="text" name="user_name" size="50" value="{{old('user_name')}}" /><br /><br />

        パスワード必須):<br />
        <input type="password" name="password" size="50" value="{{old('password')}}" /><br /><br />

        Eメール必須):<br />
        <input type="text" name="email" size="50" value="{{old('email')}}" /><br /><br />

        住所必須):<br />
        <input type="text" name="address" size="50" value="{{old('address')}}" /><br /><br />

        <input type="submit" name="confirm" value="確認"/>
    </form>
@endsection
user_confirm.blade.php
@extends('common.outerLayout')

@section('title')
    ユーザー新規登録
@endsection

@section('bodyTitle')
    <h2>確認画面</h2>
@endsection

@section('body')
    <form action="user_complete" method="post">
        @csrf
        <table border="1">
            <tr>
                <td>名前</td>
                <td>{{ $data['user_name'] }}</td>
            </tr>
            <tr>
                <td>Eメールアドレス</td>
                <td>{{ $data['email'] }}</td>
            </tr>
            <tr>
                <td>パスワード</td>
                <td>{{ $data['password'] }}</td>
            </tr>
            <tr>
                <td>住所</td>
                <td>{{ $data['address'] }}</td>
            </tr>
        </table>
        <input type="submit" name="submit" value="送信" />
        <input type="submit" name="submit" value="戻る" />
    </form>
@endsection
web.php
<?php

Route::get('/user_regist', 'UserController@getUserRegist');
Route::post('/user_confirm', 'UserController@getUserConfirm');
Route::post('/user_complete', 'UserController@postUserComplete');
UserController.php
<?php

namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests\UserRegistRequest;

class UserController extends Controller
{
    public function getUserRegist(){
        return view('user_regist');
    }

    public function getUserConfirm(Request $request){
        $data = $request->all();
        return view('user_confirm', compact('data'));
    }
UserRequest.php
<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class UserRegistRequest extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'user_name' => 'required',
            'email' => 'required',
            'password' => 'required',
            'address' => 'required'
        ];
    }

    public function messages()
    {
        return [
            'user_name.required' => '名前を入力してください',
            'email.required' => 'メールアドレスを入力してください',
            'password.required' => 'パスワードを入力してください',
            'address.required' => '住所を入力してください'//,
        ];
    }
}

本当に必要なものしか書いていません。やっぱりフレームワーク使うと簡単にできていいですね。

ajax関数の利用

このままだと、入力画面で確認ボタンを押すとPOST通信が開始されてしまうので、ボタンのtype属性をsubmitから、ただのbutton属性にします。そして、このボタンが押されたときにイベントを発生させたいので、id属性を付与しておきます

user_regist.blede.php
        <input type="button" name="confirm" value="確認" id="button"/>

次に、このボタンが押されたときに関数が実行されるように、JSを記述します。

user_regist.blede.php
    <script type="text/javascript">
        $('#button').click(function(event) {
            //ここに行いたい処理を記述
        });
    </script>

次に処理の内容を書いていきます。
まずは入力された値をJS内の変数に確保しておきます。この時、入力内容の取得はjQueryのval関数を使えば、対象要素のvalueを取得できます。
jQueryはダウンロードしてもよいですが、面倒なのでwebから直接読み込みます。

user_regist.blede.php
@section('header')
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
@endsection

//省略

    <script type="text/javascript">
        $('#button').click(function(event) {
            var user_name = $('input[name="user_name"]').val();
            var password = $('input[name="password"]').val();
            var email = $('input[name="email"]').val();
            var address = $('input[name="address"]').val();

            var data = {'user_name': user_name,
                        'password': password,
                        'email': email,
                        'address': address};
        });
    </script>

valを使うセレクタは、’タグ名[属性名=”属性値”]’ で指定しました。
また、iQueryのajaxによってJSON方式でデータを渡すには、各々のデータを連想配列で渡さないとなので、これをdata変数に作っておきます。

そしていよいよajaxを書いていきます。まずはheaderにCSRFトークンの設定を書きつつ、ajaxSetup関数でajax通信の設定を行います

user_regist.blede.php
@section('header')
    <meta name="csrf-token" content="{{ csrf_token() }}">  //追加
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
@endsection

//省略

    <script type="text/javascript">
        $('#button').click(function(event) {
            //省略

            $.ajaxSetup({
                headers: {'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')}
            });
        });
    </script>

CRSFはちょっとまだ勉強不足です。。。

次にajax関数を書いていきます

user_regist.blede.php

@section('body')
    <ul id="error_message">    //追加
    </ul>                      //追加

    //省略

    <form action="user_confirm" method="post" id="form">
    <script type="text/javascript">
        $('#button').click(function(event) {
            //省略

            $.ajax({
                url: 'user_confirm',
                type: 'POST',
                dataType: "json",
                data: data,
            }).done(function (results) {
                //通信が成功したときの処理
                console.log(results);
            }).fail(function (jqXHR, textStatus, errorThrown) {
                //通信が失敗したときの処理
                $('#error_message').empty();

                var text = $.parseJSON(jqXHR.responseText);
                var errors = text.errors;
                for (key in errors) {
                    var errorMessage = errors[key][0];
                    $('#error_message').append(`<li>${errorMessage}</li>`);
                }
            });
        });
    </script>

まずはurlで送信先のアドレスを指定します。送信方式(type)はPOSTで行います。dataTypeはjsonで、送るデータ(data)は先ほど作成したdata変数を送ります。
そして、doneとfailの中に通信後の処理を書きます。成功時は取り敢えず、console.logで結果を表示するようにします。
失敗時は箇条書き形式でメッセージを表示します。ulタグにid値をつけておいて、jQueryで指定できるようにします。

エラー内容がうまくいかないとき

次に、エラー内容がうまくいかないときは、フォームリクエストに以下を追加して、エラー内容をJSON形式で返すようにします(最初はうまくいかなかったのに、これを書いているときに再現しようとしたら、エラーがでてこなかった。。。)。

UserRegistRequest.php
use Illuminate\Foundation\Http\FormRequest;

use Illuminate\Contracts\Validation\Validator;           //追加
use Illuminate\Http\Exceptions\HttpResponseException;    //追加

//省略

    protected function failedValidation( Validator $validator )
    {
        $response['data']    = [];
        $response['status']  = 'NG';
        $response['summary'] = 'Failed validation.';
        $response['errors']  = $validator->errors()->toArray();

        throw new HttpResponseException(
            response()->json( $response, 422 )
        );
    }

成功したときの処理をどうするか?

次にvalidationを通るように入力して送信しますが...
not_json_return.png
と、エラーが返ってきて、画面遷移をしてくれません。
これは恐らく、成功時に返している内容が

UserController.php
    public function getUserConfirm(Request $request){
        $data = $request->all();
        return view('user_confirm', compact('data'));
    }

と、JSON形式のファイルではなく、viewが返っているからだと思います。
そこで、JSONのresponseをするようにcontrollerを変えますが、getUserConfirmのreturnを変えるとページ遷移ができなくなってしまうので、

  • user_regist.blade -> postUserValidation へJSONで送る
  • 結果を user_regist.blade へ送る
  • エラーが無かったら user_confirm.blade へ遷移する
    これを実装していきます。
web.php
Route::get('/user_regist', 'UserController@getUserRegist');
Route::post('/user_validation', 'UserController@postUserValidation');   //追加
Route::get('/user_confirm', 'UserController@getUserConfirm');           //変更
Route::post('/user_complete', 'UserController@postUserComplete');
UserController.php
    public function getUserRegist(){
        return view('user_regist');
    }

    public function postUserValidation(UserRegistRequest $request){
        $data = $request->all();
        $request->session()->put('data', $data);
        return response()->json([
            'data'=> $data
        ]);
    }

    public function getUserConfirm(Request $request){
        $data = $request->session()->get('data');

        return view('user_confirm', compact('data'));
    }
user_regist.blade.php
//省略

            $.ajax({
                url: 'user_validation',  //変更
                type: 'POST',
                dataType: "json",
                data: data,
            }).done(function (results) {
                //console.log(results)
                window.location.href = 'user_confirm';  //'user_confirm'へ遷移
            }).fail(function (jqXHR, textStatus, errorThrown) {

これで無事送れました!

反省

この方法だとsessionに入れなくてはいけないので、本当は直接遷移させたかったが、いろいろ調べても分からなかった...

参考にしたサイト

Laravel学習帳 Ajax入門
【Laravel5】FormRequestのバリデーション結果をJSON APIで返す

11
13
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
13

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?