Laravelでプレビュー画面を簡易に実装する方法とガッチリ実装する方法

31 回閲覧されました
みなさんこんにちは、jonioです。
今回はLaravelで投稿記事のプレビュー画面に遷移する方法を解説します。
目次
宣伝
無料で使えるLaravelの学習サイトを作りました。
ユーザー登録をしてぜひ利用して下さい。
サイトはここから。
Laravelのバージョン
10系で動作の確認をしています。
web.php
コードを下記にします。
Route::controller(PostController::class)->group(function() {
Route::get('/post/create', 'create')->name('post.create');
Route::get('/post/preview', 'preview')->name('post.preview');
});
2行目が投稿記事を作成するページ用で4行目がプレビューページ用です。
記事を作成するページのテンプレート
コードを下記にします。
<form method="POST" action="{{ route('xxxxxx') }}">
@csrf
<div>
記事のタイトル : <input type="text" name="title">
</div>
<div>
<textarea name="content"></textarea>
</div>
<div>
<button type="button" id="preview-button">プレビュー</button>
<button type="submit" name="status" value="公開">公開</button>
</div>
</form>
jQuery
コードを下記にします。
$('#preview-button').on('click', function(e) {
window.open('{{ route('post.preview') }}' + '?' + $('form').serialize(), '_blank');
});
「$(‘form’).serialize()」はフォームの中にある「<input type=”text” name=”title”>」と「<textarea name=”content”></textarea>」のname属性の値をURLに付属させます。
name属性が複数ある場合は「&」でつなぎます。
下記みたいな感じです。
http://localhost/post/preview?_token=RlK1UdaTfHsR6MgUelRXHw7K7kqFKa9lfJEBF2Eq&title=タイトル&content=内容
name属性は下記の部分です。
title=タイトル&content=内容
プレビューページを表示するコントローラー
コードを下記にします。
public function preview(Request $request)
{
$title = $request->input('title');
$content = $request->input('content');
return view('post.preview', compact('title', 'content'));
}
「$request->input(‘title’)」の意味が分からない方は下記の記事をどうぞ。
プレビューページのテンプレート
コードを下記にします。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>プレビュー</title>
</head>
<body>
<h1>{{ $title }}</h1>
<div>
{{ $content }}
</div>
</body>
</html>
これでプレビューページが動作します。
この実装方法の欠点
URLにプレビューに使うタイトルと内容を付属させましたがこの方法だとタイトル・内容が長い場合はプレビュー画面に遷移した時にエラーになります。
文字数の制限に引っかかるみたいです。
タイトル・内容が絶対に短い場合は今の方法で問題ないですが長くなる場合はこれから解説する方法で実装しましょう。
web.php
コードを下記にします。
Route::controller(PostController::class)->group(function() {
Route::get('/post/create', 'create')->name('post.create');
Route::post('/post/preview-send-data', 'previewDataSend')->name('post.preview-data');
Route::get('/post/preview', 'preview')->name('post.preview');
});
4行目を追加しています。
previewDataSendアクションからプレビューのページ(preview.blade.php)に情報を渡します。
コントローラーの修正
コードを下記にします。
use Illuminate\Support\Facades\Session;
・
・
・
public function previewDataSend(Request $request)
{
$request->validate([
'title' => 'required|max:255',
'content' => 'required',
]);
$data = [
'title' => $request->input('title'),
'content' => $request->input('content')
];
Session::put('preview_data', $data);
return response()->json(['success' => true]);
}
public function preview()
{
view()->share('title', 'プレビュー');
$data = Session::get('preview_data');
$title = $data['title'];
$content = $data['content'];
return view('post.preview', compact('title', 'content'));
}
今回のポイントは13行目と29行目でセッションを使います。
13行目は下記の形式で使用します。
Session::put('名称', 変数);
今回は変数にタイトルと内容(14行目〜17行目)を使って名称は「preview_data」に設定しています。
設定したセッションのデータを29行目で取得します。
29行目は下記の形式で使用します。
Session::put('名称');
名称は13行目と同じにします。
jQuery
記事を作成するページのjQueryのコードを下記にします。
$('#preview-button').on('click', function(e) {
e.preventDefault();
let form = $('form');
let formData = new FormData(form[0]);
$.ajax({
url: '{{ route("post.preview-data") }}',
method: 'POST',
data: formData,
contentType: false,
processData: false,
success: function() {
window.open('{{ route('post.preview') }}', '_blank');
},
error: function(xhr, status, error) {
console.error('プレビュー用データ送信エラー:', xhr.responseText);
alert('プレビューに失敗しました。タイトルと内容を入力して下さい。');
}
});
});
プレビューページのテンプレート
このページのコードはそのままで大丈夫です。
記事を編集するページjQuery
おまけで解説します。
記事を作成するページとコードを同じにするとデベロッパーツールを見た時に下記のエラーが出ます。
"message": "The PUT method is not supported for route post/preview-send-data. Supported methods: GET, HEAD, POST.",
この時のweb.phpのコードは下記です。
Route::get('/post/{id}/edit', 'edit')->name('post.edit');
テンプレートのコードは下記です。
<form method="POST" action="{{ route('post.update', ['id' => $target->id]) }}" enctype="multipart/form-data" class="mt-5">
@csrf
@method('put')
<div>
記事のタイトル : <input type="text" name="title" placeholder="記事のタイトル" value="{{ old('title', $target->title) }}">
</div>
<div class="summernote mt-3">
<textarea name="content" id="summernote" cols="30" rows="10"> {{ old('content', $target->content) }}</textarea>
</div>
<div class="mt-3">
<button type="button" id="preview-button" class="btn-info border-0 mr-1">プレビュー</button>
</div>
</div>
</form>
jQueryのコードを少し変更します。
$('#preview-button').on('click', function(e) {
e.preventDefault();
let form = $('form');
let formData = new FormData(form[0]);
formData.set('_method', 'POST'); //この行を修正
$.ajax({
url: '{{ route("post.preview-data") }}',
method: 'POST',
data: formData,
contentType: false,
processData: false,
success: function() {
window.open('{{ route('post.preview') }}', '_blank');
},
error: function(xhr, status, error) {
console.error('プレビュー用データ送信エラー:', xhr.responseText);
alert('プレビューに失敗しました。タイトルと内容を入力して下さい。');
}
});
});
8行目を修正しています。
HttpリクエストメソッドがPUTなのをPOSTに変換してプレビューページを表示できるようにしています。
これで完成です。