laravelのbladeをVue.jsで書き換える【Form編】

#はじめに
プログラミング学習をはじめ、１０カ月です。
現在はLravelとVue.jsを学習しています。

この組み合わせだと世間的には、SPAと決まっているのですか？

Vueも少しずつわかってきたので、laravelのbladeをVueに書き替えて、MPAを作り始めました。

基本のCRUD処理をと思いましたが、さっそくつまずきました。

## register画面を作ろう

laravelやVue.jsの基本は理解している前提で進めていきます。

ポイントを押さえながら解説します

まずは基本となるregister.phpです。

```html:register.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <meta name="csrf-token" content="{{ csrf_token() }}">　//①
　　//中略（cssなど）
    <title>title</title>
</head>
<body>
    <div id="app">
        <registerform-component 
            :old="{{ json_encode(Session::getOldInput()) }}"　//②
            :errors= "{{ $errors }}">　//③
        </registerform-component>
    </div>
    <script src="{{ mix('js/app.js') }}"></script>
</body>
```

htmlではポイントは３つ
①laravelではcsrf対策を取らないといけません。
headにトークンを仕込んでおきます

②フォームで重要なのは入力ミスがあった場合、元のフォームにリダイレクトされます。入力した内容は残って欲しいですよね。
laravelのbladeでは、oldヘルパーが使えたのですが、Vueでは使えませんでした。
ここはあとで解説します。

③入力ミスがあった場合、何が間違っているのか、バリデーションによるエラーメッセージが表示されます。
laravelでは$errorsでどこからでも拾ってこれるそうですね。

>\$errors変数はwebミドルウェアグループに所属する、Illuminate\View\Middleware\ShareErrorsFromSessionミドルウェアによりビューに結合されます。このミドルウェアが適用される場合は、いつでもビューの中で\$errors変数が使えます。$errors変数はいつでも定義済みであると想定でき、安心して使えます。
https://readouble.com/laravel/5.5/ja/validation.html

しかし、これもVueの中では素直に使えませんでした。

##Componentを作ろう
今回はRegisterForm.Vueを作成しました。
予め使えるようコンポーネントの登録はしておいてください。

```javascript:RegisterForm.Vue
<template>
    <form action="/register" method="POST"> //④

        <input type="hidden" name="_token" :value="csrf"> //⑤

        <div class="form-group">
            <label>名前</label>
            <strong class="error" v-for="value in error.name">{{ value }}</strong> //⑥
            <input class="form-control" name="name" type="text" v-model="name"> //⑦
        </div>
        <div class="form-group">
            <label>Email</label>
            <strong class="error" v-for="value in error.email">{{ value }}</strong>
            <input class="form-control" name="email" type="text" v-model="email">
        </div>
        <div class="form-group">
            <label>パスワード</label>
            <strong class="error" v-for="value in error.password">{{ value }}</strong>
            <input class="form-control" name="password" type="password"  v-model="password" autocomplete="off">
        </div>
        <div class="form-group">
            <label>再入力</label>
            <input class="form-control" name="password_confirmation" type="password" v-model="password_confirmation" autocomplete="off">
        </div>

        <input type="submit"  class="button" value="登録"> //⑧
    </form>
</template>

<script> //⑨
    export default {
        props:[
            'old',
            'errors'
        ],
        data:function(){
            return{
                csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content'),
                name: this.old.name,
                email:this.old.email,
                password:'',
                password_confirmation:'',
                error:{
                    name:this.errors.name,
                    email:this.errors.email,
                    password:this.errors.password,
                }
            }
        },
    }
```

コンポーネントはこんな感じにしました。

④register登録は/registerにPOSTします。

⑤laravelではPOSTデータにcsrfトークンを仕込まないと、弾かれてしまいます。
scriptタグで取得したトークンをもたせます。
```csrf: document.querySelector('meta[name="csrf-token"]').getAttribute('content')```

これは、このコンポーネントが入るregister.phpのheadに記述したものをとってきています。

⑥ここはエラー文ですね。後述します。

⑦はVueの基本の双方向バインディングですね。
Vーmodelでinputが変更されると、dataも変更されます。

⑧でサブミットされますね。



先述の
```<registerform-component
:old="{{ json_encode(Session::getOldInput()) }}"　//②
:errors= "{{ $errors }}">　//③
</registerform-component>
```
の③で
コンポーネントに変数＄errorsを渡します。
コンポーネント内ではpropで使用することができます。

同様に②で入力したデータはセッションに保存されています。
これをgetOldInput()で取得できます。
これをjson_encode（）でjsonデータに直してコンポーネントに渡しています。

propで受け取ったデータは、thisで使用できます。
dataの初期値にthisで取得したデータを入れることで、入力したデータやエラーメッセージを表示させることができます。


##まとめ
こうして、無事にフォームができたのでした。
かなり時間かかりましたが、なんとかなりました。
コンポーネントは複雑化させていきますので、
次はvuexを導入します。