2
3

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 1 year has passed since last update.

【Laravel Sail × Editor.js】リッチテキストエディタのデータをAjaxで保存する

Last updated at Posted at 2022-12-30

現在エンジニアを目指して勉強中です。

ポートフォリオ作品にEditor.jsを導入したので、実装の内容をまとめました。
導入~出力 / データ整形~保存 / 画面表示・再編集 / 画像プラグイン /
の4部作となっています。(現在進行中)

今回はデータ整形~保存までです。

環境

・macOS Monterey 12.6
・PHP 8.1.13
・Laravel 9.3.12
・MySQL 8.0.31
・Docker 20.10.2
・Laravel Sail

おさらいと今回の概要

前回の記事で、エディタに入力したデータが
JSON形式で出力されるところまで確認しました

// 出力されるデータ
// 出力されるJSONオブジェクトは以下のように3つのプロパティを含んでいる
{time: 1672207762160, blocks: Array(2), version: '2.26.4'}

// blocksのなかにテキスト情報が含まれる
blocks:[
    {
     id  : "J4ZvhsriKq",
     type:"paragraph",
     data:{
            text:"ああああああ"
           }
    },
    {
     id  :"El6S5s-QoM",
     type:"list",
     data:{
            style:"ordered",
            items:[
                    "ほほおほほほおほほほほh<br>ほほほほほほほほほほほ",
                    "ほほおほほほほほほほほほ"
                   ]
           }
    }
]

今回はこのEditor.jsのデータをinputタグの情報と一緒に送信し、
保存するまでを実装していきます。

データの整形

不要なプロパティの削除

タイムスタンプとバージョン情報は不要なので、落とします。
jsでは、オブジェクトから複数のプロパティを一括削除できる方法がないらしいので
こちらの記事のやり方で実装。

editor.js
editor.save()
  .then((outputData) => {
    console.log('Article data: ', outputData);

    // ここで不要なプロパティを削除
    ['time', 'version'].forEach(e => delete outputData[e]);
    console.log('Processed data: ', outputData);
  })
  .catch((error) => {console.log('Saving failed: ', error)});

// 出力
Article data:  {time: 1672212255124, blocks: Array(2), version: '2.26.4'}
Processed data:  {blocks: Array(2)}

文字列へ変換

MySQLではJSON型のテーブルも作れるようですが、
今回はtext型でデータを保存しておきます。

JSON.stringifyメソッドで文字列型へ変換。

editor.js
let text = '';

editor.save()
  .then((outputData) => {
      ['time', 'version'].forEach(e => delete outputData[e]);
      text = JSON.stringify(outputData);
  })

これで、Editor.jsblocksの内容が
JSON形式の文字列としてtextに格納されました。

inputタグのデータ取得

今回保存はinputタグの入力データも一緒に保存するので、
そのデータの取得も行います。

editor.html
<!-- Laravelプロジェクトなので実際はeditor.blade.phpファイル -->
<input type="text" name="input1" class="js-get-input1">
<input type="text" name="input2" class="js-get-input2">

<!-- Editor.jsのデータ -->
<div id="editor" class="form_editor"></div>

<!-- ボタンを押すとイベント発火 -->
<button type="button" class="js-save-data">保存する</button>
editor.js
$(function() {

  // 保存するデータ
  $('.js-save-data').on('click', function() {
    let input1 = $('.js-get-input1').val();
    let input2 = $('.js-get-input2').val();
    let text = '';

    editor.save()
      .then((outputData) => {
          ['time', 'version'].forEach(e => delete outputData[e]);
          text = JSON.stringify(outputData);
      })
      .catch((error) => {console.log('Saving failed: ', error)});
  });
});

データベースへ送信

db構造

以下のようなイメージです

名前 タイプ
id bigint
user_id bigint
data1 varchar(255)
data2 int(11)
text text

ajax通信

今回はajaxでデータを送信します

editor.js
$(function() {
  $('.js-save-note').on('click', function() {
    let input1 = $('.js-get-input1').val();
    let input2 = $('.js-get-input2').val();
    let text = '';

    editor.save()
      .then((outputData) => {
          ['time', 'version'].forEach(e => delete outputData[e]);
          text = JSON.stringify(outputData);
          ///////////////////////////////
          // ここからajax通信
          $.ajax({
            method: 'POST',
            url: '/hoge',
            data: {data1: input1, data2: input2, text: text}
          })
          .done(function() {
            window.location = ('/home');
          })
          .fail(function() {
             console.log('失敗');
          });
      })
      .catch((error) => {console.log('Saving failed: ', error)});
  });
});

Laravel側の設定

ここは、formタグで値を保存するときと同じ。

app/Models/Hoge.php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Hoge extends Model
{
    use HasFactory;

    protected $fillable = [
      'user_id',
      'data1',
      'data2',
      'text'
    ];

    public function user() {
      return $this->belongsTo(User::class);
    }
}
app/Http/Requests/Hoge/CreateRequest.php
namespace App\Http\Requests\Note;
use Illuminate\Foundation\Http\FormRequest;

class CreateRequest extends FormRequest
{
    public function authorize()
    {
        return true;
    }

    public function rules()
    {
    // ここがバリデーション
        return [
          'data1' => 'required|integer|max:47',
          'data2' => 'required|string|max:255',
          'text' => 'required|json'
        ];
    }
}
app/Http/Controllers/HogeController.php
namespace App\Http\Controllers;

use App\Http\Requests\Hoge\CreateRequest;
use App\Models\Hoge;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class HogeController extends Controller
{
  public function store(CreateRequest $request) {
    $hoge = new Hoge;
    $hoge->user_id = Auth::id();    // user_idを格納
    $hoge->fill($request->all());   // ajaxのデータを格納
    $hoge->save();                  // 保存
  }
}

エラー

ここまでを実装する中で、以下2つのエラーが発生。
419 (unknown status)
422 (Unprocessable Content)

解決のために3つのことを確認しました

  1. csrfトークン
  2. モデル内の$fillableの設定
  3. ログイン状況

CSRFトークン

Laravelでpost送信をしようとすると求められる。
ajax通信を使う場合は、それ用の記載が必要

editor.js
$.ajax({
/////////////////////////
// これがajax通信用のcsrfトークンの記載
headers: {
  'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
},
/////////////////////////

method: 'POST',
url: '',
data: {text: text}
})
.done(function() {
})
.fail(function() {
});

$fillableの設定

$fillable内にuser_idを指定し忘れていました。。。
指定したカラムのみが操作できるようになるので、
user_idがnullになってしまいエラーが発生していた。

*fillableやguardedについては↓

ログイン状況

これは我ながらアホすぎるミスなのですが、
ログインしていない状態で作業していたため、
user_idが無限に取得できない状況になっていました。

開発段階でミドルウェアの設定をしてない時などはお気をつけください。。。

おまけ:フラッシュメッセージの追加

ここからはプラスアルファですが、
登録が完了したら、それを通知するメッセージを表示したい。

Laravelにはフラッシュメッセージ用のflashメソッドが用意されているので
それを使います。

セッションにフラッシュメッセージを持たせる

app/Http/Controllers/HogeController.php

class HogeController extends Controller
{
  public function store(CreateRequest $request) {
    $hoge = new Hoge;
    $hoge->user_id = Auth::id();
    $hoge->fill($request->all()); 
    $hoge->save();                  

    // フラッシュメッセージを追加
    session()->flash('session_success', '保存が完了しました'); 
  }
}

フラッシュメッセージ表示のhtmlを追加

layouts/app.html
<!-- Laravelプロジェクトなので実際はapp.blade.phpファイル -->
<!-- ここまでヘッダー -->

<!-- フラッシュメッセージがある時だけ表示したいので@if -->
@if(session('session_success'))
<!-- Session Message -->
<div class="flashMsg flashMsg--success js-show-flashMsg">
  <p class="flashMsg_text js-get-flashMsg">{{ session('session_success') }}</p>
</div>
@endif

<!-- ここからコンテンツ -->

cssとjsで表示

cssは割愛しますが、activeクラスの付け外しで
transform: translateXを適用させて動かします

app.js
$(function () {

  let msgWindow = $('.js-show-flashMsg');

  if ($('.js-get-flashMsg').text()) {
    msgWindow.toggleClass('active');
    setTimeout(function(){
      msgWindow.toggleClass('active');
    }, 4000);
  }
});

参考

公式

その他

2
3
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
2
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?