「Laravel」カテゴリーアーカイブ

【ダイエット支援】食事管理機能を検討する。

ダイエット支援ツールは以下のリンク先で運用中です。

https://taki-lab.site:8443

ダイエット支援ツールに食事管理機能を追加したいと思います。

ダッシュボードはこんな感じにしようと思います。

三栄要素をレーダーチャートで表示させます。

Chart.jsを調べたらこんな感じのチャートが表示出来るみたいです。

また、この画面からデータ入力も出来るようにしたいと思います。

詳細画面はこんな感じ。

日付毎に三栄要素とカロリーを一覧表示。

さらに編集画面へのリンクを用意します。

編集画面はこんな感じ。

朝昼晩毎に、食事と栄養素とカロリーを表示します。

入力、編集も可能にします。

その他、ちょっとFitBitアプリの機能っぽいものに仕上げたいと思います。

じゃあ、次回から取りかかりますか。

【Laravel】【ダイエット支援】グラフをもっと簡潔に【完成】

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

このプログラムはこちらのリンク先で運用中です。

https://taki-lab.site:8443

前回からあれこれ考えたのですが、

3つのデータを1つのグラフに表示させようというのがよろしくないという結論になりました。

リンクのクリックでグラフを体重、体脂肪率、BMIで切り替えるようにしました。

たいした修正では無いので、ソースは書きませんが、gitHubのソースコードを参照してもらえればと思います。

ついでに軸の設定も変えました。(最大値と最小値)

かなりスッキリして見やすくなったかな。

やっぱりグラフは多くて2つまでかな、と思います。

さて、体重記録機能はほぼ完了しました。

次は・・・食事記録かな・・・。

【LARAVEL】【ダイエット支援】グラフのデータ間隔を指定する

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

このプログラムはこちらのリンク先で運用中です。

https://taki-lab.site:8443

さて、こちらのグラフなんですが、

現状は最近の10日間のデータをグラフに表示させているのですが、

実際、もっと昔のデータもグラフに出したいじゃないですか。

なので、これをやります。

UIとしては、右下のところに日毎、週毎、月毎のリンクを作成して、それでグラフの切り替えをやっていこうと思います。

まずはフロント部分。

            <div class="command">
                <ul>
                    <li><a @click="onClickDay">day</a></li>
                    <li><a @click="onClickWeek">week</a></li>
                    <li><a @click="onClickMonth">month</a></li>
                </ul>
                <ul>
                    <li><a @click="onClickInput">クイック入力</a></li>
                    <li><a href="/weight">詳細</a></li>
                </ul>
            </div>

こんな感じでリンクを作ります。

フロントの処理はこちら。

        onClickDay: function() {
            this.contents.interval = 1;
            this.graphUpdate();
        },
        onClickWeek: function() {
            this.contents.interval = 7;
            this.graphUpdate();
        },
        onClickMonth: function() {
            this.contents.interval = 30;
            this.graphUpdate();
        },

クリックするリンクでデータ間隔を数字で設定して、APIのパラメータとして与えます。

ではAPIの処理。

    /**
     * グラフ用データを取得する
     */
    public function graph(Request $request)
    {
        return response()->json(['datas' => $this->weightManagement->getGraphData(Auth::user(), $request->contents["interval"])]);
    }
    public function getGraphData($user, $interval, $days = 10)
    {
        $datetimes = [];
        for($i = 0; $i < $days ; $i++) {
            $datetimes[] = date('Y-m-d', strtotime('today - '.($i * $interval).' day'));
        }

        return $user->WeightManagements()
                    ->whereIn(DB::raw('date_format(datetime, "%Y-%m-%d")'), $datetimes)
                    ->get();
    }

実行結果はこちら。

日毎

週毎

月毎

データが少ないからあまり違いがわかりませんが、表示はちゃんと変わってます。

【LARAVEL】【ダイエット支援】ページネーションを実装する

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

データ一覧画面にページネーション機能を追加します。

1画面に表示するデータの数を絞り、ページ切り替えによって表示するデータを切り替えるというものです。

データの数が多くなったらこういう機能も必要になると思います。

やり方は主に2つありまして、

一つは、一度すべてのデータを取得し、その後はフロント側でよしなにするパターン。

もう一つは、ページ切り替えをするごとに必要なデータを取得するパターンです。

今回は後者の方を採用しようと思います。

まずは、データ数からページ数を求める処理を作成し、ページ切り替えの機能を作成していきます。

リポジトリの実装。

    public function getTotalRecord($user)
    {
        return $user->WeightManagements()->count();
    }

count()でデータ数が取れるんですね。便利。

コントローラーの実装。

    /**
     * データのレコード数を取得する
     */
    public function total(Request $request)
    {
        return response()->json(['total' => $this->weightManagement->getTotalRecord(Auth::user())]);
    }
Route::post('api/weight/total', 'Weight\ApiController@total');

ページを表示したら、このAPIを使用するようにします。

    created: function() {
        this.updateList();
        this.createPagenate();
    },
    methods: {
        createPagenate: function() {
            var self = this;
            this.pagenates = [];
            axios.post('api/weight/total').then(function(response){
                var total = response.data.total;
                self.maxPage = Math.floor(total / 10) + 1;
                for(var i = 1; i <= self.maxPage; i++) {
                    self.pagenates.push(i);
                }
            }).catch(function(error){
            });
        },

APIでデータ数を取得し、そこからページ数とページネーションのリスト(1,2,3…)をリストで作成します。

これを使用して、テンプレートを作成します。

            <div id="pagenate">
                <ul>
                    <li>
                        <a href="#" v-if="prevShow" @click="prevPage()">&lt;</a>
                        <b v-else>&lt;</b>
                    </li>
                    <li v-for="page in pagenates">
                        <a href="#" v-if="currentPage != page" @click="changePage(page)">{{ page }}</a>
                        <b v-else>{{ page }}</b>
                    </li>
                    <li>
                        <a href="#" v-if="nextShow" @click="nextPage()">&gt;</a>
                        <b v-else>&gt;</b>
                    </li>
                </ul>
            </div>

前のページ(<)、ページ数指定、次のページ(>)の順に表示させています。

ただ、1ページ目に場合は前のページが非活性化、最大ページのときは次のページが非活性化、あとは、現在のページと同じページへのリンクが非活性化させる必要があります。

これはv-ifで表示を切り替えています。

判定はcomputedで実装しています。

    computed: {
        prevShow: function() {
            return this.currentPage != 1;
        },
        nextShow: function() {
            return this.currentPage != this.maxPage;
        },
    },

あとは、ページをクリックしたときの処理を作成していきます。

        changePage: function(page) {
            this.currentPage = page;
            this.updateList();
        },
        nextPage: function() {
            this.currentPage += 1;
            if(this.currentPage > this.maxPage) {
                this.currentPage = this.maxPage;
            }
            this.updateList();
        },
        prevPage: function() {
            this.currentPage -= 1;
            if(this.currentPage <= 0) {
                this.currentPage = 0;
            }
            this.updateList();
        },

リスト更新処理も修正します。

        updateList: function() {
            this.datalists = [];
            this.contents.page = this.currentPage;
            this.param.contents = this.contents;
            var self = this;
            axios.post('api/weight/list', this.param).then(function(response){
                response.data.dataLists.forEach(element => {
                    self.datalists.push({
                        id: element.id,
                        date: element.datetime,
                        weight: element.weight,
                        fat_rate: element.fat_rate,
                        bmi: element.bmi
                    })
                });
            }).catch(function(error){
            });
        }
    /**
     * データを取得する
     */
    public function list(Request $request)
    {
        return response()->json(['dataLists' => $this->weightManagement->list(Auth::user(), $request->contents["page"])]);
    }
    public function list($user, $page = 1)
    {
        return $user->WeightManagements()
                    ->orderBy('datetime', 'desc')
                    ->skip(10 * ($page - 1))
                    ->limit(10)
                    ->get();
    }

日付で降順に並べ替え、ページの開始から10件取得する、という処理に変更しています。

実行結果はこちら。

【LARAVEL】【ダイエット支援】VPSにデプロイする

前回までの状況はこちら。

最低限必要な機能は出来上がったので、本番サーバであるVPSで稼働させます。

gitからソースファイルをクローン

git clone https://github.com/takishita2nd/diet-mng.git

パーミッション変更

chmod -R 777 storage/
chmod 777 bootstrap/cache/

.envを作成し、データベースの設定と、URLの設定を記入。

cp .env.example .env
vi .env

データベースにログインし、データベースを作成。

mysql> create database diet_mng;

composerを使ってLaravelの環境を構築

sudo apt-get install composer
composer install

.envにkyeを生成

php artisan key:generate

npmでVue.jsを使用できるようにする

sudo apt-get install npm
sudo apt-get install libpng-dev
npm install
npm run prod

データベース構築(マイグレート)

php artisan migrate

nginxの設定

URLでブログとダイエット管理を分けようと思ったのですが、上手く設定できなかったので、ポート番号で分けます。

cd /etc/nginx/sites-enabled
sudo cp default laravel
sudo vi laravel
server {
        listen 8443 ssl default_server;
        listen [::]:8443 ssl default_server;
        ssl_certificate     /etc/letsencrypt/live/taki-lab.site/fullchain.pem;
        ssl_certificate_key /etc/letsencrypt/live/taki-lab.site/privkey.pem;

        root /var/www/html/diet-mng/public;

        index index.php index.html index.htm index.nginx-debian.html;

        server_name taki-lab.site;

        location / {
                try_files $uri $uri/ /index.php?$query_string;
        }

        location ~ \.php$ {
                fastcgi_pass   unix:/run/php/php7.2-fpm.sock;
                fastcgi_index  index.php;
                fastcgi_param  SCRIPT_FILENAME  $document_root/index.php;
                include        fastcgi_params;
        }
}

ポート番号は8443を使用しました。

ブログ用の設定では動きませんので、いろんなサイトを調べた結果、このような設定で動作できます。

rootはプロジェクトディレクトリ/publicを指定します。publicの下のindex.phpにアクセスするように指定します。

nginxの設定と読み込み

sudo systemctl reload nginx.service

何も表示されなければ書式は合っています。

エラーが出たら/var/log/nginx/error.logを確認してください。

ここまで上手くいけばトップページが表示されるはず。

トップページ書き換えるの忘れてた。

ログインしてデータ入力できることを確認する。

以下、詰まったところ

modelに以下を記入しないとデータベースクエリが動かなかった。

protected $table = 'weight_managements';

https://qiita.com/igz0/items/d14fdff610dccadb169e

テーブル名を明示的に指定しないといけないらしい。

ここらへん、ローカル環境にフィードバックさせます。

というわけで、

ダイエット管理サイト、以下からアクセスできますので、よかったら使ってみてください。

https://taki-lab.site:8443/

【LARAVEL】【ダイエット支援】グラフ表示用のデータを取得するその2

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

前回はAPI側を作成したので、今回はフロント側を作成します。

使用したライブラリは、chart.jsです。

なんか、Vue.js用に拡張されたvue-chart.jsというものもあるみたいなのですが、うまく動かなかったので、chart.jsにしました。

原因はわからん。

npm install chart.js --save

でインストール。

resouces/assets/app.jsに以下を書き込みます。

require('chart.js');

これでどこでもchart.jsが使えます。

<template>
    <div>
        <div class="dashboard">
            <div class="chart">
                <canvas id="weight"></canvas>
            </div>
            <div class="command">
                <ul>
                    <li><a @click="onClickInput">クイック入力</a></li>
                    <li><a href="/weight">詳細</a></li>
                </ul>
            </div>
        </div>
        <weight-input-dialog-component :show="showInputDialogContent" @update="invokeUpdateList"></weight-input-dialog-component>
    </div>
</template>

<script>
export default {
    data() {
        return {
            showInputDialogContent: false,
            datetimeList: [],
            weightList: [],
            fat_rateList: [],
            bmiList: [],
        };
    },
    created: function() {
    },
    mounted: function() {
        this.graphUpdate();
    },
    methods: {
        onClickInput: function() {
            this.showInputDialogContent = true;
        },
        invokeUpdateList: function() {
            this.graphUpdate();
        },
        graphUpdate: function() {
            this.datetimeList = [];
            this.weightList = [];
            this.fat_rateList = [];
            this.bmiList = [];
            var ctx = document.getElementById("weight");
            var self = this;
            axios.post('api/weight/graph').then(function(response){
                response.data.datas.forEach(element => {
                    self.datetimeList.push(element.datetime);
                    self.weightList.push(element.weight);
                    self.fat_rateList.push(element.fat_rate);
                    self.bmiList.push(element.bmi);
                });
                var myChart = new Chart(ctx, {
                    type: 'line',
                    data: {
                        labels: self.datetimeList,
                        datasets: [
                            {
                                yAxisID: 'weight',
                                label: '体重(kg)',
                                data: self.weightList,
                                borderColor: "rgba(255,0,0,1)",
                                backgroundColor: "rgba(0,0,0,0)"
                            },
                            {
                                yAxisID: 'fat_rate',
                                label: '体脂肪率(%)',
                                data: self.fat_rateList,
                                borderColor: "rgba(0,255,0,1)",
                                backgroundColor: "rgba(0,0,0,0)"
                            },
                            {
                                yAxisID: 'bmi',
                                label: 'BMI',
                                data: self.bmiList,
                                borderColor: "rgba(0,0,255,1)",
                                backgroundColor: "rgba(0,0,0,0)"
                            },
                        ]
                    },
                    options: {
                        title: {
                            display: true,
                            text: '最近の記録',
                        },
                        elements: {
                            line: {
                                tension: 0,
                            }
                        },
                        scales: {
                            yAxes: [
                                {
                                    id: 'weight',
                                    type: 'linear',
                                    position: 'left',
                                    ticks: {
                                        suggestedMax: 100,
                                        suggestedMin: 0,
                                        stepsize: 10,
                                        callback: function(value, index, values){
                                            return value + 'kg';
                                        }
                                    }
                                },
                                {
                                    id: 'fat_rate',
                                    type: 'linear',
                                    position: 'right',
                                    ticks: {
                                        suggestedMax: 100,
                                        suggestedMin: 0,
                                        stepsize: 10,
                                        callback: function(value, index, values){
                                            return value + '%';
                                        }
                                    }
                                },
                                {
                                    id: 'bmi',
                                    type: 'linear',
                                    position: 'left',
                                    ticks: {
                                        suggestedMax: 100,
                                        suggestedMin: 0,
                                        stepsize: 10,
                                        callback: function(value, index, values){
                                            return value;
                                        }
                                    }
                                },
                            ]
                        }
                    }
                });
            }).catch(function(error){
            });
        }
    }
}
</script>

var ctx = document.getElementById(“weight”);でcanvasの要素を取得し、var myChart = new Chart(ctx, {…})で{…}の部分にデータを入れることで、canvasにグラフが描画されます。

axiosのpostメソッドを使用して、前回作成したAPIを呼び出し、表示するデータを項目ごとにリスト化してchart.jsに渡します。

動作結果はこんな感じ。

思ったよりいい感じです。

【LARAVEL】【ダイエット支援】グラフ表示用のデータを取得する

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

これからダッシュボードに表示するグラフを作成するんですが、それに使用するデータの取得を行います。

今回グラフに表示するのは、最近10日間のデータのみ、という想定をしています。

    public function getGraphData($user)
    {
        $datetimes = [];
        for($i = 0; $i < 10 ; $i++) {
            $datetimes[] = date('Y-m-d', strtotime('today - '.$i.' day'));
        }

        return $user->WeightManagements()
                    ->whereIn(DB::raw('date_format(datetime, "%Y-%m-%d")'), $datetimes)
                    ->get();
    }

今回のポイントは特定ユーザに関連するデータのみを対象にする場合、

$user->WeightManagements()->whereIn()

という感じで、リレーションからのSQLビルダ作成、というやり方ができるらしい。

前回のホテル予約管理ではjoinやらwhereやら使いまくっててコードがごちゃごちゃしていたけど、その必要はなかった。

ただし、ここからgroupbyやら統計関連の関数を使用するとうまく行かない。

どうやら、laravelさんがget()の出力内容にuser_idなどの情報を含めているためにグループ化ができないため、SQL実行エラーとなるようです。

なので、一日の最新を取り出す、ということになると、このやり方ではSQLビルダは使用できなくって、PHP側で処理することになります。

今回はめんどくさいので、最新10日のデータ全部、としました。

きちんとtinkerで動作確認したよ。

    /**
     * グラフ用データを取得する
     */
    public function graph(Request $request)
    {
        return response()->json(['datas' => $this->weightManagement->getGraphData(Auth::user())]);
    }
Route::post('api/weight/graph', 'Weight\ApiController@graph');
>>> $rep->getGraphData($user)
=> Illuminate\Database\Eloquent\Collection {#3849
     all: [
       App\Model\WeightManagement {#3843
         id: 1,
         datetime: "2020-05-28 02:14:00",
         weight: "80.00",
         fat_rate: "17.00",
         bmi: "27.00",
         created_at: "2020-05-28 02:14:50",
         updated_at: "2020-05-28 02:14:50",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3840
           user_id: 1,
           weight_management_id: 1,
         },
       },
       App\Model\WeightManagement {#3844
         id: 2,
         datetime: "2020-05-28 02:15:00",
         weight: "80.00",
         fat_rate: "17.00",
         bmi: "27.00",
         created_at: "2020-05-28 02:15:10",
         updated_at: "2020-05-28 02:15:10",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3841
           user_id: 1,
           weight_management_id: 2,
         },
       },
       App\Model\WeightManagement {#3845
         id: 5,
         datetime: "2020-05-28 02:34:00",
         weight: "80.00",
         fat_rate: "17.00",
         bmi: "28.00",
         created_at: "2020-05-28 02:34:49",
         updated_at: "2020-06-01 01:20:56",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3779
           user_id: 1,
           weight_management_id: 5,
         },
       },
       App\Model\WeightManagement {#3846
         id: 9,
         datetime: "2020-05-31 02:44:00",
         weight: "87.00",
         fat_rate: "17.00",
         bmi: "17.00",
         created_at: "2020-05-31 02:44:36",
         updated_at: "2020-05-31 02:44:36",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3834
           user_id: 1,
           weight_management_id: 9,
         },
       },
       App\Model\WeightManagement {#3847
         id: 10,
         datetime: "2020-06-02 02:03:00",
         weight: "87.80",
         fat_rate: "15.90",
         bmi: "27.00",
         created_at: "2020-06-02 02:03:29",
         updated_at: "2020-06-02 02:03:29",
         pivot: Illuminate\Database\Eloquent\Relations\Pivot {#3848
           user_id: 1,
           weight_management_id: 10,
         },
       },
     ],
   }

【LARAVEL】【ダイエット支援】データ一覧画面からデータ削除

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

データ削除処理を作成します。

とはいっても、もう追加、編集処理が出来上がっているので、そんなに難しくありませんでした。

ぱぱっとやってしまいます。

    public function delete($id, $user)
    {
        $model = $this->getItemById($id);
        $this->detachToUser($model, $user);
        $model->delete();
    }
    /**
     * データを1件削除する
     */
    public function delete(Request $request)
    {
        $this->weightManagement->delete($request->contents["id"], Auth::user());
        
        return response()->json();
    }
Route::post('api/weight/delete', 'Weight\ApiController@delete');
<template>
    <div>
        <div id="overlay" v-show="show">
            <div id="content">
                <p v-if="error_flg == true" class="error">
                    <ui>
                        <li v-for="error in errors">{{ error }}</li>
                    </ui>
                </p>
                <table class="edit">
                    <tbody>
                        <tr>
                            <td>日時</td>
                            <td>{{contents.date}}</td>
                        </tr>
                        <tr>
                            <td>体重</td>
                            <td>{{contents.weight}}</td>
                        </tr>
                        <tr>
                            <td>体脂肪</td>
                            <td>{{contents.fat_rate}}</td>
                        </tr>
                        <tr>
                            <td>BMI</td>
                            <td>{{contents.bmi}}</td>
                        </tr>
                    </tbody>
                </table>
                <p id="command">
                    <button @click="clickDelete">OK</button>
                    <button @click="closeModal">キャンセル</button>
                </p>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    props: ['show'],
    data() {
        return {
            errors: [],
            error_flg: [],
            param: {},
            contents: {
                date: "",
                weight: "",
                fat_rate: "",
                bmi: "",
            },
        };
    },
    created: function() {
    },
    methods: {
        dataSet: function(data) {
            this.contents = data;
        },
        clickDelete: function() {
            var self = this;
            this.param.contents = this.contents;
            axios.post('api/weight/delete', this.param).then(function(response){
                self.closeModal();
                self.$emit('update');
            }).catch(function(error){
                self.error_flg = true;
                self.errors = error.response.data.errors;
            });
        },
        closeModal: function() {
            this.$parent.showDeleteDialogContent = false;
        },
    }
}
</script>
            <weight-delete-dialog-component ref="deleteDialog" :show="showDeleteDialogContent" @update="invokeUpdateList"></weight-delete-dialog-component>
        onClickDelete: function(id) {
            var editData = {};
            this.datalists.forEach(element => {
                if(element.id == id){
                    editData.id = id;
                    editData.date = element.date;
                    editData.weight = element.weight;
                    editData.fat_rate = element.fat_rate;
                    editData.bmi = element.bmi;
                    return true;
                }
            });
            this.$refs.deleteDialog.dataSet(editData);
            this.showDeleteDialogContent = true;
        },

いいかんじです。

【LARAVEL】【ダイエット支援】データ一覧画面からデータ更新

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

データ編集・更新できるようにします。

まず、編集ダイアログのコンポーネントですが、入力のときと別物にしましょう。

同じコンポーネントも使えるかもしれないけど、いろいろめんどくさい。

<template>
    <div>
        <div id="overlay" v-show="show">
            <div id="content">
                <p v-if="error_flg == true" class="error">
                    <ui>
                        <li v-for="error in errors">{{ error }}</li>
                    </ui>
                </p>
                <table class="edit">
                    <tbody>
                        <tr>
                            <td>体重</td>
                            <td><input type="number" v-model="contents.weight" /></td>
                        </tr>
                        <tr>
                            <td>体脂肪</td>
                            <td><input type="number" v-model="contents.fat_rate" /></td>
                        </tr>
                        <tr>
                            <td>BMI</td>
                            <td><input type="number" v-model="contents.bmi" /></td>
                        </tr>
                    </tbody>
                </table>
                <p id="command">
                    <button @click="clickAdd">入力</button>
                    <button @click="closeModal">閉じる</button>
                </p>
            </div>
        </div>
    </div>
</template>
<script>
export default {
    props: ['show'],
    data() {
        return {
            errors: [],
            error_flg: [],
            param: {},
            contents: {
                id: "",
                weight: "",
                fat_rate: "",
                bmi: "",
            },
        };
    },
    created: function() {
    },
    methods: {
        dataSet: function(data) {
            this.contents = data;
        },
        clickAdd: function() {
            var self = this;
            this.param.contents = this.contents;
            axios.post('api/weight/edit', this.param).then(function(response){
                self.clear();
                self.closeModal();
                self.$emit('update');
            }).catch(function(error){
                self.error_flg = true;
                self.errors = error.response.data.errors;
            });
        },
        closeModal: function() {
            this.$parent.showEditDialogContent = false;
        },
        clear: function() {
            this.contents.weight = "";
            this.contents.fat_rate = "";
            this.contents.bmi = "";
            this.error_flg = false;
            this.errors = [];
        }
    }
}
</script>

そして、それを使用する側の親コンポーネント。

        <div>
            <weight-input-dialog-component :show="showInputDialogContent" @update="invokeUpdateList"></weight-input-dialog-component>
            <weight-edit-dialog-component ref="editDialog" :show="showEditDialogContent" @update="invokeUpdateList"></weight-edit-dialog-component>
        </div>
        onClickEdit: function(id) {
            var editData = {};
            this.datalists.forEach(element => {
                if(element.id == id){
                    editData.id = id;
                    editData.weight = element.weight;
                    editData.fat_rate = element.fat_rate;
                    editData.bmi = element.bmi;
                    return true;
                }
            });
            this.$refs.editDialog.dataSet(editData);
            this.showEditDialogContent = true;

ポイントは、編集ダイアログにデータを渡すとき。

親コンポーネントから子コンポーネントのメソッドをコールしています。

これは、子コンポーネントを定義するときに、

ref="editDialog"

と書くことで、

            this.$refs.editDialog.dataSet(editData);

と、子コンポーネントのメソッドを実行できます。

その引数でパラメータを渡して、表示させています。

あとは、今までどおり。

Repository

    public function edit($id, $weight, $fat_rate, $bmi)
    {
        $model = $this->getItemById($id);
        $model->weight = $weight;
        $model->fat_rate = $fat_rate;
        $model->bmi = $bmi;
        $model->save();
    }

    public function getItemById($id)
    {
        return WeightManagement::where(['id' => $id])->first();
    }

controller

    /**
     * データを1件更新する
     */
    public function edit(Request $request)
    {
        $param = $this->weightManagement->getParam();
        $this->weightManagement->edit( $request->contents["id"], 
            $request->contents["weight"],
            $request->contents["fat_rate"],
            $request->contents["bmi"]
        );
        
        return response()->json();
    }
Route::post('api/weight/edit', 'Weight\ApiController@edit');

【LARAVEL】【ダイエット支援】データ一覧画面からデータ入力

前回までの状況はこちら。

最新ソースはこちら(gitHub)

https://github.com/takishita2nd/diet-mng

データ一覧画面からデータ入力を行います。

<template>
    <div>
        <div>
            <p id="navi">> <a href="/home">HOME</a></p>
            <p id="inputbutton">
                <button @click="onClickInput">データ入力</button>
            </p>
            <table class="weightlist">
                <tbody>
                    <tr>
                        <th class="date">日時</th>
                        <th class="weight">体重(kg)</th>
                        <th class="fat_rate">体脂肪(%)</th>
                        <th class="bmi">BMI</th>
                        <th class="edit"></th>
                        <th class="delele"></th>
                    </tr>
                    <tr v-for="data in datalists">
                        <td class="date">{{ data.date}}</td>
                        <td class="weight">{{ data.weight}}</td>
                        <td class="fat_rate">{{ data.fat_rate}}</td>
                        <td class="bmi">{{ data.bmi}}</td>
                        <td class="edit"><a href="">Edit</a></td>
                        <td class="delele"><a href="">Delete</a></td>
                    </tr>
                </tbody>
            </table>
        </div>
        <div>
            <weight-input-dialog-component :show="showDialogContent" @update="invokeUpdateList"></weight-input-dialog-component>
        </div>
    </div>
</template>

入力ダイアログ画面は、すでに作成してあるコンポーネントを流用します。

しかし、この一覧画面から入力した場合は、入力後、リストを更新する必要があります。

なので、入力ダイアログコンポーネントから親コンポーネントで信号を送って、リスト更新処理を走らせるようにします。

入力処理はこんな感じ。

        clickAdd: function() {
            var self = this;
            this.param.contents = this.contents;
            axios.post('api/weight/add', this.param).then(function(response){
                self.clear();
                self.closeModal();
                self.$emit('update');
            }).catch(function(error){
                self.error_flg = true;
                self.errors = error.response.data.errors;
            });
        },

ポイントは、親側(データ一覧画面)側で

<weight-input-dialog-component :show="showDialogContent" @update="invokeUpdateList"></weight-input-dialog-component>

@update=”invokeUpdateList”の部分。

これがある状態で、子コンポーネントから

this.$emit('update');

を実行すると、親コンポーネントのinvokeUpdateList()メソッドが実行されます。

    created: function() {
        this.updateList();
    },
    methods: {
        onClickInput: function() {
            this.showDialogContent = true;
        },
        invokeUpdateList: function() {
            this.updateList();
        },
        updateList: function() {
            this.datalists = [];
            var self = this;
            axios.post('api/weight/list').then(function(response){
                response.data.dataLists.forEach(element => {
                    self.datalists.push({
                        date: element.datetime,
                        weight: element.weight,
                        fat_rate: element.fat_rate,
                        bmi: element.bmi
                    })
                });
            }).catch(function(error){
            });
        }
    }

こんな感じで更新処理を行えばOK。

ちなみに、ダッシュボード画面(:@updateの記載がない)に対して$emit(‘update’)を行っても特にエラーにはなりませんでした。

子コンポーネント定義に書かなければ、emitしても何事もなく動くみたいです。