tohokuaikiのチラシの裏

技術的ネタとか。

Vuejsのコンポーネントを使ってsyncとかデータのやり取り

登録と編集って同じフォームを使いまわすので、Componentにしてあれこれできないかなと思ってたら、意外とデータを親子のVueでやり取りするのが面倒そうで…

を参考に。

上記の記事の問題点

なんで、子コンポーネントでまたpropsを定義し直さないと…というのが死ぬほど嫌だったので、考えた。ES2015を全然知らないのに考えた。

とりあえずこんなかんじ。

親側 Create.vue

<template>
    <div>
        <order-form
          v-bind.sync="order"
          ></order-form>
    </div>
</template>
<script>
import OrderFrom "@/components/OrderForm";
import defaultOrder from "@/helper/order";
export default {
    components: {
        'order-form': OrderForm,
    },
    data() {
        return {
            order: (new defaultOrder).props(),
        }
    }
}
</script>

子側 OrderForm.vue

<template>
    <div>
            <div class="form-group">
                <label>お名前</label>
                <input type="text" :value="name"
                       @input="$emit('update:name', $event.target.value)"
                       :class="{'form-control':true, 'error': false}">
            </div>
            <div class="form-group">
                <label>メールアドレス</label>
                <input type="text" :value="email"
                       @input="$emit('update:email', $event.target.value)"
                       :class="{'form-control':true, 'error':false}">
            </div>
            <div class="form-group">
                <label>電話番号</label>
                <input type="text" :value="tel"
                       @input="$emit('update:tel', $event.target.value)"
                       :class="{'form-control':true, 'error':false}">
            </div>
    </div>
</template>
<script>
import defaultOrder from "@/helper/order";
export default {
    props: (new defaultOrder()).defs,
    data() {
    },
};
</script>

Orderの定義ファイル

helper/order.js

export default class defaultOrder {
    constructor() {
        this.defs = {
          email: {
            type: String,
            default: ""
          },
          name: {
            type: String,
            default: ""
          },
          tel: {
            type: String,
            default: ""
          },
        };
    }
    
    props(){
        let prop = {};
        for (let p in this.defs){
            prop[p] = this.defs[p].default;
        }
        return prop;
    }
};

みたいな。

でもダメだね。

これ、Modelを一括で渡すには良いけど、他のプロパティが渡せない。 ダメだわ。普通に1個づつ渡すしか無いな。

axiosでParallel実行する時のエラーハンドリングがよくわからない

axiosで並列して全部終わったら…というやつ。

axios.all([
    axios.get('/api/user/'),
    axios.get('/api/image')
]).then(([res1, res2]) => {
    this.user = res1.data;
    this.image = res2.data;
}).catch(err =>{
    console.log(err);
});

ってやると、2つgetしたうちの最初のエラーしかcatchしてくれない。

個々のエラーを見たかったら

axios.all([
    axios.get('/api/user/').catch(err => { /*  error処理 */ }),
    axios.get('/api/image').catch(err => { /*  error処理 */ })
]).then(([res1, res2]) => {
    this.user = res1.data;
    this.image = res2.data;
});

という感じに個々のaxiosにcatchを付ける。でも、これだとthenにいっちゃう。

それが嫌なら

axios.all([
    axios.get('/api/user/').catch(err => { /*  error処理 */ throw(err); }),
    axios.get('/api/image').catch(err => { /*  error処理 */  throw(err);})
]).then(([res1, res2]) => {
    this.user = res1.data;
    this.image = res2.data;
}).catch(err =>{
    console.log(err);
});

ってやると、catchできるけどそれって最初のとあんま変わんないっていう…。

LaravelでEthnaのフォームフィルターみたいなやつ

あれな。Inputの時にPOST値を自動的に全角から半角にしてくれたりするやつ。あれ、すげー便利なんだけど、Laravel本体にはないらしい。

waavi/sanitizerをインストール

composerにあるので https://packagist.org/packages/waavi/sanitizer

$ composer require waavi/sanitizer

でインストール

Filterクラスを作成

App/Http/Requests/Filters ディレクションを作成してクラスを登録。applyメソッドを作る。

<?php
namespace App\Http\Requests\Filters;

use Waavi\Sanitizer\Contracts\Filter;

/**
 * Class Zentohan
 */
class Zentohan implements Filter
{
    /**
     * @param mixed $value
     * @param array $options
     * @return mixed|string|string[]
     */
    public function apply($value, $options = [])
    {
        return mb_convert_kana($value, 'KVa', 'UTF-8');
    }
}

Requestクラスで使う

Validator前にFilterしてくれる。

<?php
namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;
use Waavi\Sanitizer\Laravel\SanitizesInput;
use App\Http\Requests\Filters\Zentohan;

class UserRequest extends FormRequest
{
    use SanitizesInput;

    /**
     * @return array filters before sanitized
     */
    public function filters()
    {
        return [
            'name'  => 'zentohan',
            'email' => ['zentohan', 'lowercase'],
        ];
    }

    public function customFilters()
    {
        return [
            'zentohan' => Zentohan::class
            ];
    }
}

うーん、便利。

filtersは配列で複数、あるいは|でつないで複数いける。

Vuejsの共通関数の設置

utility.jsとかにして全体で使いたい場合ありますよね。methodsに突っ込みます。

mixin用のファイル作成

my_vue_mixin.js

export default{
  methods: {
    aaa(){
        console.log('123');
    }
  }
}

Vueに仕込む

app.js

import Vue from 'vue';
import myVueMixin from './my_vue_mixin';
window.Vue = require('vue');
Vue.mixin(myVueMixin);

const app = new Vue({
    el: '#app',
});

この2行ね

import myVueMixin from './my_vue_mixin';
Vue.mixin(myVueMixin);

Vueファイルで使う

普通にmethodsのメンバーとして使える。 Foo.vueで

    methods: {
        confirm(){
            this.aaa();
        }

とか。

traitのメソッドをoverwriteしたんだけど、そのoverwriteされたメソッドを呼びたい場合

参考にさせていただきました

qiita.com ありがとうございました。

試行錯誤してみる

まずは基本となるtraitのAと親クラスBaseを定義

<?php
trait A
{
    public function say()
    {
        echo "I am A\n";
    }
}

class Base
{
    public function say()
    {
        echo "I am Base\n";
    }
}

で、Baseを継承しAをtraitしたクラスを作る

<?php
class Sayer extends Base
{
    use A ;

    public function say()
    {
        echo "I am Sayer\n";
    }
}

このSayerクラスのsay()メソッドからtraitのsay()メソッドをコールしたいわけです。

単純にparentを使った

<?php
class Sayer extends Base
{
    use A ;

    public function say()
    {
        echo "I am Sayer\n";
        parent::say();
        $this->sayA();
    }
}

(new Sayer())->say();

結果

I am Sayer
I am Base

そりゃー、そーですよね。parentは継承元のクラスなんで…

単純に$this->を使った

<?php
class Sayer extends Base
{
    use A;
    
    public function say()
    {
        echo "I am Sayer\n";
        $this->say();
    }
}
(new Sayer())->say();

結果

I am Sayer
I am Sayer
...(略:252回繰り返す)
I am Sayer
I am Sayer
PHP Fatal error:  Uncaught Error: Maximum function nesting level of '256' reached, aborting! in /home/vagrant/work/trait_parent.php:22

メソッドループして怒られた。…当たり前だな。

解決方法

use ... as を使う

<?php
class Sayer extends Base
{
    use A {
        A::say as sayA;
    }
    
    public function say()
    {
        echo "I am Sayer\n";
        $this->sayA();
    }
}
(new Sayer())->say();

結果

I am Sayer
I am A

無事traitのメソッドが呼び出せた。