現在エンジニアを目指して勉強中です。
ポートフォリオ作品に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.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
メソッドで文字列型へ変換。
let text = '';
editor.save()
.then((outputData) => {
['time', 'version'].forEach(e => delete outputData[e]);
text = JSON.stringify(outputData);
})
これで、Editor.js
のblocks
の内容が
JSON形式の文字列としてtext
に格納されました。
inputタグのデータ取得
今回保存はinput
タグの入力データも一緒に保存するので、
そのデータの取得も行います。
<!-- 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>
$(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でデータを送信します
$(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タグで値を保存するときと同じ。
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);
}
}
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'
];
}
}
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つのことを確認しました
- csrfトークン
- モデル内の
$fillable
の設定 - ログイン状況
CSRFトークン
Laravelでpost送信をしようとすると求められる。
ajax通信を使う場合は、それ用の記載が必要
$.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
メソッドが用意されているので
それを使います。
セッションにフラッシュメッセージを持たせる
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を追加
<!-- 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
を適用させて動かします
$(function () {
let msgWindow = $('.js-show-flashMsg');
if ($('.js-get-flashMsg').text()) {
msgWindow.toggleClass('active');
setTimeout(function(){
msgWindow.toggleClass('active');
}, 4000);
}
});
参考
公式
その他