Laravelでブログサイトを作る 18. 管理画面・記事編集の際に入力補助を(TinyMCE)

はじめに
記事を編集する際に、HTMLの入力補助を行えるようにします。
様々なライブラリが存在しますが、TinyMCEを使用します。
画像のアップロード機能を組み込むことができるので(次回解説予定)、という理由で
選定しました。
導入方法
- JSファイルをダウンロードし、
public/jsに配置する- CDNを使うと、日本語化で手こずる懸念と、バージョンアップに引きずられて問題が発生する可能性があるため、ファイルをダウンロードします。
- テンプレートファイルに、JSの読み込みと初期化構文を記述する
1. JSファイルのダウンロード
ダウンロードは、コチラから可能です。
ページ中程にある「Download TinyMCE Community」から本体を、「Download Language Pack」から日本語パックをダウンロードし、解凍します。
本体は、public/jsに配置します。
その後、langディレクトリに日本語パックのja.jsを移動します。
最終的には、以下のような形です。
public/
└ js/
└ tinymce/
├ lang
| └ ja.js ←日本語パックから移動
└ その他、jquery.tinymce.min.js など
テンプレート
resources/views/admin/articleEdit.blade.php
JSファイルの読み込みと、初期化についての記述を追加するだけで、便利なTinyMCEが使えるようになります。
日本語化せずにCDNを使う場合は、前述のダウンロード云々もスキップできるので、非常に簡単です。
@section('adminMain')
{{-- 省略 --}}
<h3>記事本文</h3>
<textarea name="body">{{ $articleData->body ?? '' }}</textarea>
{{-- 省略 --}}
<script src="{{ asset('/js/tinymce/tinymce.min.js') }}"></script>
<script>
tinymce.init({
selector:'textarea',
language: "ja"
});
</script>
@endsection
参考文献
TinyMCEを設置する
https://qiita.com/nissuk/items/e31bdfa858d6c5c018c2
Laravelでブログサイトを作る 17. フロントページ

はじめに
今回の、フロント側作成によって、ブログは一応の完成となります。
カテゴリを管理し、記事を作成編集でき、それを表示する。ごくごくシンプルな構成ですが、ブログとしての最低限が備わった状態になります。
そしてその作業ですが、実はほとんどありません。
Controller
app/Http/Controllers/ArticleController.php
一覧
ルーティングの際に設定した、一覧表示画面を用意します。
新着順、親子カテゴリの絞り込み、検索。前々回、前回で、管理画面で用意したものとほとんど同じです。
違う点は、以下の2つ。
- 削除済み記事を出さない→
getList()の第2引数をfalseにしてあげればOKです - フロント用のテンプレートを使う→
listView()の第2引数をfrontに変更
/**
* 記事一覧
*
* @return mixed
*/
public function list() {
// ブログ記事一覧を取得
$articleData = $this->article->getList($this->ADMIN_LIST_NUM, false);
return $this->listView($articleData, 'front');
}
/**
* 親カテゴリ別記事一覧
*
* @param string $parent
* @return mixed
*/
public function parentList(string $parent) {
// ブログ記事一覧を取得
$articleData = $this->article->getList($this->ADMIN_LIST_NUM, false, (int)$parent);
return $this->listView($articleData, 'front');
}
/**
* 子カテゴリ別記事一覧
*
* @param string $child
* @return mixed
*/
public function childList(string $child) {
// ブログ記事一覧を取得
$articleData = $this->article->getList($this->ADMIN_LIST_NUM, false, 0, $child);
return $this->listView($articleData, 'front');
}
/**
* 記事一覧(ワード検索)
*
* @param Request $request
* @return mixed
*/
public function searchList(Request $request) {
// ブログ記事一覧を取得
$articleData = $this->article->getList($this->ADMIN_LIST_NUM, false, 0, 0, $request['search']);
return $this->listView($articleData, 'front');
}
記事詳細
① 記事取得
記事テーブルと親カテゴリテーブルのJoinは、カテゴリ名を取得するための連結です。後述の子カテゴリ同様に、記事の終わりにカテゴリ別一覧へのリンク生成に使います。
一覧のようにget()を使うのではなく、first()を使っているのは、主キーで検索しているからです。
② 記事と関連付けられている子カテゴリの情報を取得
記事のIDが固定なので、そこに関連する子カテゴリを取得します。関連付けテーブルと子カテゴリテーブルをJoinして、カテゴリ名も取得します。
/**
* 記事詳細
*
* @param string $id
* @return mixed
*/
public function content(string $id) {
// ① 記事取得
$articleData = $this->article
// 親カテゴリについても取得
->leftJoin(
'parent_categories',
function ($join) {
$join->on('articles.parent', '=', 'parent_categories.id');
}
)
// ID指定して1件分のデータを取得
->where('articles.id', $id)->first();
if ($articleData === null) {
// 記事データが見つからない場合はエラー出力する
return $this->error('warning', '記事が見つかりません。');
}
// ② 記事と関連付けられている子カテゴリの情報を取得
$articleChildrenData = $this->articleChild
->leftJoin('child_categories', function ($join) {
$join->on('article_children.children', '=', 'child_categories.id');
})->where('article_children.article', $id)->get();
// 親カテゴリを取得
$parentCategoryList = $this->parentCategory->orderBy('number', 'asc')->orderBy('id', 'asc')->get();
// 子カテゴリは、キーを親カテゴリIDにした連想配列にする
$data = $this->childCategory->orderBy('number', 'asc')->orderBy('id', 'asc')->get();
$childCategoryList = [];
foreach ($data as $item) {
$childCategoryList[$item->parent][] = $item;
}
return view('front.article', [
'articleData' => $articleData,
'articleChildrenData' => $articleChildrenData,
'parentCategoryList' => $parentCategoryList,
'childCategoryList' => $childCategoryList,
]);
}
/**
* エラー出力
*
* @param string $type
* @param string $message
* @return mixed
*/
public function error(string $type, string $message) {
// $typeに特定文字列以外を指定させない
if (!in_array($type, ['information', 'caution', 'warning'])) {
$type = 'information';
}
return view('front.error', [
'type' => $type,
'message' => $message,
]);
}
テンプレート
記事詳細
resources/views/front/article.blade.php
あまり、特筆することはありません。記事のタイトルと本文を表示し、属するカテゴリの表示と、それぞれの絞り込み一覧へのリンクを生成しています。
@extends('front.app')
@section('title')
{{ $articleData->title }}
@endsection
@section('main')
<article>
<section class="article">
{{-- 記事タイトル --}}
<h2>{{ $articleData->title }}</h2>
{{-- 本文 --}}
{!! $articleData->body !!}
{{-- 親子カテゴリ --}}
<div class="articleCategory">
<ul>
<li>
<a href="{{ route('list_parent', ['id' => $articleData->parent]) }}">
{{ $articleData->name }}
</a>
</li>
@foreach ($articleChildrenData as $articleChildren)
<li>
<a href="{{ route('list_child', ['id' => $articleChildren->children]) }}">
{{ $articleChildren->name }}
</a>
</li>
@endforeach
</ul>
</div>
{{-- 公開日時 --}}
<p class="articleDate">{{ $articleData->created_at }}</p>
</section>
</article>
@endsection
エラー
resources/views/front/error.blade.php$typeはエラーレベルを指定するイメージです。ひとまず「通知(information)」「注意(caution)」「警告(warning)」を想定しています。
@section('title', 'エラー')
@section('main')
<article>
<section class="article">
<div class="{{ $type }}"><p>{{ $message }}</p></div>
</section>
</article>
@endsection
Laravelでブログサイトを作る 16. 管理機能・記事一覧の絞り込みと検索

はじめに
前回で記事一覧を作成した続きになります。
Model
app/Models/Article.php
前回作成した一覧取得メソッドを拡張します。
引数に、今回追加分が未指定の場合の初期値を設定しているので、既存の呼び出し箇所に変更は不要となります。
// ...省略...
/**
* 一覧取得
*
* @param int $num 件数
* @param bool $delete 削除済みを含めるか(true => 含める)
* @param int $parent 親カテゴリID 【今回追加】
* @param int $children 子カテゴリID 【今回追加】
* @param string $search 検索ワード 【今回追加】
* @return mixed
*/
public function getList(
int $num,
bool $delete = false,
int $parent = 0,
int $children = 0,
string $search = '')
{
$article = $this;
// 【今回追加】親カテゴリが指定されている場合、記事テーブルのカラムと一致するものを抽出する
if ($parent !== 0) {
$article = $article->where('articles.parent', '=', $parent);
}
// 【今回追加】子カテゴリが指定されている場合、テーブルをJOINする
if ($children !== 0) {
$article = $article
// 記事テーブルと、記事-子カテゴリ関連付けテーブルをJOIN
->leftJoin('article_children', function ($join) {
$join->on('articles.id', '=', 'article_children.article')
->where('article_children.deleted_at', '=', NULL);
})
// 子カテゴリテーブルと、記事-子カテゴリ関連付けテーブルをJOIN
->leftJoin('child_categories', function ($join) {
$join->on('child_categories.id', '=', 'article_children.children');
})
// 子カテゴリの一致するものを抽出する
->where('child_categories.id', '=', $children);
}
// 【今回追加】検索ワードが指定されている場合
if ($search !== '') {
$article = $article
// タイトルか本文のどこかに検索ワードが含まれていれる記事を抽出する
->where(function($query) use ($search) {
$query->where('articles.title', 'like', '%'.$search.'%')
->orWhere('articles.body', 'like', '%'.$search.'%')
;
});
}
// 削除済みを含む場合は`withTrashed()`
if ($delete !== true) {
$article = $article->withTrashed();
}
// ソートは、新しい記事を上位表示
$article = $article->orderBy('open', 'desc');
// 取得
return $article->paginate($num);
}
// ...省略...
Controller
ルーティングで設定したメソッドを用意し、それぞれのパラメータを変更して一覧取得します。
その後は、表示用メソッドlistView()を実行するだけです。
// ...省略...
/**
* 管理画面・親カテゴリ別記事一覧
*
* @param string $parent
* @return mixed
*/
public function adminParentList(string $parent) {
// ブログ記事一覧を取得
$articleData = $this->article->getList($this->ADMIN_LIST_NUM, true, (int)$parent);
return $this->listView($articleData, 'admin');
}
/**
* 管理画面・子カテゴリ別記事一覧
*
* @param string $child
* @return mixed
*/
public function adminChildList(string $child) {
// ブログ記事一覧を取得
$articleData = $this->article->getList($this->ADMIN_LIST_NUM, true, 0, $child);
return $this->listView($articleData, 'admin');
}
/**
* 管理画面・記事一覧(ワード検索)
*
* @param Request $request
* @return mixed
*/
public function adminSearchList(Request $request) {
// ブログ記事一覧を取得
$articleData = $this->article->getList($this->ADMIN_LIST_NUM, true, 0, 0, $request['search']);
return $this->listView($articleData, 'admin');
}
// ...省略...
テンプレート
resources/views/admin/app.blade.php
サイドメニューに、検索ボックスとカテゴリの絞り込みリンクを設置します。
// ...省略...
<section class="aside">
<h3>検索</h3>
<div id="searchWrapper">
<form action="{{ route('admin_article_list_search') }}" method="post" name="searchForm">
{{ csrf_field() }}
<input type="text" id="searchTxt" name="search" placeholder="サイト内検索" />
<a href="javascript:searchForm.submit()" id="searchBtn">
<i class="fas fa-search"></i>
</a>
</form>
</div>
</section>
@if (isset($parentCategoryList))
<section class="aside">
<h3>カテゴリ</h3>
<ul>
@foreach ($parentCategoryList as $parent)
<li>
<a href="{{ route('admin_article_list_parent', ['parent' => $parent->id]) }}">
{{ $parent->name }}
</a>
@if (isset($childCategoryList[$parent->id]))
<ul>
@foreach ($childCategoryList[$parent->id] as $child)
<li>
<a href="{{ route('admin_article_list_child', ['child' => $child->id]) }}">
{{ $child->name }}
</a>
</li>
@endforeach
</ul>
@endif
</li>
@endforeach
</ul>
</section>
@endif
// ...省略...
Laravelでブログサイトを作る 15. 管理機能・記事一覧画面

はじめに
記事の一覧表示は、管理側とフロント側でほとんど同じものを用意することになります。
相違点は以下の2点ですので、それを踏まえて作成します。
- 削除済みの内容を表示するかどうか
- 使用するテンプレート
Model
app/Models/Article.php
一覧取得のためのメソッドをModelに記載します。
今回は「削除済みを含むか」だけですが、今後は「絞り込み(親カテゴリ、子カテゴリ)」「検索」についてもコチラを編集する予定です
<?php
// ...省略...
class Article extends Model
{
// ...省略...
/**
* 一覧取得
*
* @param int $num 件数
* @param bool $delete 削除済みを含めるか(true => 含める)
* @return mixed
*/
public function getList(int $num, bool $delete = false) {
$article = $this;
// 削除済みを含む場合は`withTrashed()`
if ($delete !== true) {
$article = $article->withTrashed();
}
// ソートは、新しい順に表示
$article = $article->orderBy('open', 'desc');
// 指定件数を取得
return $article->paginate($num);
}
}
Controller
app/Http/Controllers/ArticleController.php
「一覧取得する」「表示する」という工程に分けて考えます。後に、絞り込みや検索した際に、「表示する」アルゴリズムは共通なので、listView()を作成し、表示処理を行っています。
<?php
// ...省略...
class ArticleController extends Controller
{
// ...省略...
private $ADMIN_LIST_NUM = 30; // 管理画面での記事一覧表示件数
// ...省略...
/**
* 管理画面・記事一覧
*
* @return mixed
*/
public function adminList() {
// ブログ記事一覧を取得
$articleData = $this->article->getList($this->ADMIN_LIST_NUM, true);
return $this->listView($articleData, 'admin');
}
/**
* 記事の一覧表示
*
* @param object $articleData
* @param string $type
* @return mixed
*/
private function listView(object $articleData, string $type = 'front') {
// 親カテゴリを取得
$parentCategoryList = $this->parentCategory->orderBy('number', 'asc')->orderBy('id', 'asc')->get();
// 子カテゴリは、キーを親カテゴリIDにした連想配列にする
$data = $this->childCategory->orderBy('number', 'asc')->orderBy('id', 'asc')->get();
$childCategoryList = [];
foreach ($data as $item) {
$childCategoryList[$item->parent][] = $item;
}
return view($type . '.articleList', [
'articleData' => $articleData,
'parentCategoryList' => $parentCategoryList,
'childCategoryList' => $childCategoryList,
]);
}
}
テンプレート
resources/views/admin/articleList.blade.php
ページの移動には、独自に作成したテンプレートを使用しています。これについては、後述します。
@extends('admin.app')
@section('adminTitle', '記事一覧')
@section('paging')
<nav>
{{ $articleData->links('pagination') }}
</nav>
@endsection
@section('adminMain')
<article>
<section class="article">
<h2>記事一覧</h2>
<table>
<tr>
<th style="width:200px;">サムネイル</th>
<th>タイトル</th>
</tr>
@foreach ($articleData as $item)
{{-- 本文中の最初の画像をサムネイルとして扱う --}}
<?php preg_match('/<img.+src=[\'"](?P<src>.+?)[\'"].*>/i', $item->body, $image); ?>
<tr {!! ($item->private === 1) ? 'style="background-color: #cccccc;"' : '' !!}>
<td><img src="{{ $image['src'] ?? '/img/no_image.jpg' }}" /></td>
<td>
{{-- タイトル(クリックしたら編集画面へ) --}}
<a href="{{ route('admin_article_edit', ['id' => $item->id]) }}">{{ $item->title }}</a>
{{-- タイトルと本文を水平線で区切る --}}
<hr />
{{-- 本文は、タグを除いた先頭200文字だけを表示させる --}}
{!! mb_substr(strip_tags($item->body), 0, 200) !!}
</td>
</tr>
@endforeach
</table>
</section>
</article>
@endsection
独自定義のページネーション
resources/views/pagination.blade.php
先述のテンプレートに出てきた、{{ $articleData->links('pagination') }}で、ページネーションのHTMLを作成しています。
$articleDataは、Modelで検索条件を付けた後に$article->paginate($num);の戻り値が入っています。
このpaginate()の返り値に対して、->links()で、基本的なページネーションができます。テンプレート名を渡してやれば、対象のファイルを使ってくれます。
@if ($paginator->hasPages())
<ul class="pagination">
{{-- 現在が1ページ目でなければ、最初へ遷移するリンクを設置 --}}
@if (!$paginator->onFirstPage())
<li>
<a href="{{ $paginator->url(1) }}">最初</a>
</li>
@endif
{{-- ページ番号を使用したリンクを設置 --}}
@foreach ($elements as $element)
@if (is_array($element))
@foreach ($element as $page => $url)
@if ($page === $paginator->currentPage())
{{-- 現在のページ番号には、リンクを設置しない --}}
<li class="active" aria-current="page"><span>{{ $page }}</span></li>
@elseif (($page - 2) <= $paginator->currentPage() && ($page + 2) >= $paginator->currentPage())
{{-- 2ページ前~2ページ次までのページ番号を表示 --}}
<li><a href="{{ $url }}">{{ $page }}</a></li>
@endif
@endforeach
@endif
@endforeach
{{-- Next Page Link --}}
@if ($paginator->hasMorePages())
<li>
<a href="{{ $paginator->url($paginator->lastPage()) }}">最後</a>
</li>
@endif
</ul>
@endif
Laravelでブログサイトを作る 14. 管理機能・記事編集画面から新規登録まで

今回のゴール
記事を作成し、保存するところまで。
編集することも考慮した作りにすること。
Controller
インスタンスの生成等
useに記載した、Illuminate\Support\Facades\DBは、トランザクション処理のためです。
(親子カテゴリでは実装漏れです。後で対応しました)
<?php
namespace App\Http\Controllers;
use App\Models\Article;
use App\Models\ArticleChild;
use App\Models\ChildCategory;
use App\Models\ParentCategory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
class ArticleController extends Controller
{
protected $article;
protected $articleChild;
protected $childCategory;
protected $parentCategory;
/**
* 新しいコントローラインスタンスの生成
*
* @param Article $article
* @param ArticleChild $articleChild
* @param ChildCategory $childCategory
* @param ParentCategory $parentCategory
* @return void
*/
function __construct(
Article $article,
ArticleChild $articleChild,
ChildCategory $childCategory,
ParentCategory $parentCategory)
{
$this->article = $article;
$this->articleChild = $articleChild;
$this->childCategory = $childCategory;
$this->parentCategory = $parentCategory;
}
入力画面
editメソッドの最後、画面表示はeditView()を作成して行っています。
これは、"更新に失敗した時"の場合に、変更した内容をそのままに再表示させたいので、ArticleとArticleChildだけが違う入力画面表示として用意しました。
- 通常:DBのArticleとArticleChildを取得して、画面表示
- 更新失敗:入力内容をそのままに、画面表示
としたいので、「画面表示」の部分だけ共通化した形です。
/**
* 記事内容入力画面
*
* @param string|null $id
* @return mixed
*/
public function edit(string $id = null) {
// 記事情報を取得(存在しない場合はnull)
$articleData = $this->article->withTrashed()->where('id', $id)->first();
// 記事と子カテゴリの連携データは、テンプレートで使いやすいように子カテゴリIDをキーにしておく
$list = $this->articleChild->where('article', $id)->get();
$articleChildData = [];
foreach ($list as $item) {
$articleChildData[$item->children] = 'on';
}
// 編集画面表示
return $this->editView($articleData, $articleChildData);
}
/**
* 記事内容入力画面の生成
*
* @param $articleData
* @param $articleChildData
* @param $message
* @return mixed
*/
private function editView($articleData, $articleChildData, $message = '') {
// 親子カテゴリを取得(削除状態のカテゴリを設定しないように、withTrashed()はつけない)
$parentCategoryData = $this->parentCategory->orderBy('number', 'asc')->orderBy('id', 'asc')->get();
$childCategoryData = $this->childCategory->orderBy('number', 'asc')->orderBy('id', 'asc')->get();
return view('admin.articleEdit', [
'articleData' => $articleData,
'articleChildData' => $articleChildData,
'parentCategoryData' => $parentCategoryData,
'childCategoryData' => $childCategoryData,
'message' => $message,
]);
}
更新処理
Articleの登録更新は、カテゴリと同様に対応できます。
ArticleChildについては、一旦すべての子カテゴリを取得し、それぞれにチェックが入っているかを確認しています。
チェックボックスで子カテゴリを選択する予定なので、チェックしない(関連付けない)場合、情報がPOSTされません。なので、全部の子カテゴリのうち、チェックされているものを有効に、チェック情報が存在しないものを無効に、という考えです。
/**
* 記事情報更新
*
* @param Request $request
* @return mixed
*/
public function update(Request $request)
{
// 入力値取得
$id = $request['id'];
$tiitle = $request['title'];
$body = $request['body'];
$parent = $request['parent'];
$childList = $request['child'];
$open = $request['open'];
$private = $request['private'];
// トランザクション開始
DB::beginTransaction();
try {
// 記事データ保存
$articleData = $this->article->withTrashed()->where('id', $id)->first();
if ($articleData === null) {
$articleData = new Article();
}
$articleData->title = $tiitle;
$articleData->body = $body;
$articleData->parent = $parent;
$articleData->open = $open;
$articleData->private = $private;
$articleData->save();
// 記事-子カテゴリの連携(削除検出のため、子カテゴリ全件取得)
$childCategoryData = $this->childCategory->withTrashed()->get();
foreach ($childCategoryData as $item) {
// 連携データを取得
$articleChildData = $this->articleChild->withTrashed()
->where('article', $articleData->id)->where('children', $item->id)->first();
if (isset($childList[$item->id]) && $childList[$item->id] === 'on') {
// チェックが入っている => insert or restore
if ($articleChildData === null) {
$articleChildData = new ArticleChild();
$articleChildData->article = $articleData->id;
$articleChildData->children = $item->id;
$articleChildData->save();
} else {
$articleChildData->restore();
}
} else if ($articleChildData !== null) {
// チェックが入っていない => 以前に作られていたら削除
$articleChildData->delete();
}
}
// コミット
DB::commit();
// 完了表示
//return redirect()->route('admin_article_list');
return redirect()->route('admin_article_edit', ['id' => $articleData->id]);
} catch (\Exception $e) {
// 処理失敗時はロールバック
DB::rollback();
// 入力内容をそのままに、編集画面再表示
return $this->editView(
$articleData,
$childList,
'DBの書き込みに失敗しました。[' . $e->getMessage() . ']'
);
}
}
}
テンプレート
resources/views/admin/articleEdit.blade.php
{{ $hoge ?? 'fuga' }}は、「変数$hogeが存在するなら$hogeの内容を表示し、なければfugaを表示」します。
子カテゴリのlabelタグに記載しているdata-parentは、JavaScript側での制御に利用します。属する親カテゴリIDを持たせ、表示/非表示を切り替えます。
@extends('admin.app')
@section('adminTitle', '記事作成編集')
@section('adminMain')
<article>
@if ($message !== '')
<section class="article">
<p>{{ $message }}</p>
</section>
@endif
<section class="article">
<h2>記事作成編集</h2>
<form method="post">
<input type="hidden" name="id" value="{{ $articleData->id ?? '' }}" />
<h3>記事タイトル</h3>
<input type="text" name="title" value="{{ $articleData->title ?? '' }}" />
<h3>親カテゴリ</h3>
<select name="parent" id="articleEditParent">
@foreach ($parentCategoryData as $parent)
<option value="{{ $parent->id }}" {{ ($articleData !== null && $articleData->parent == $parent->id) ? 'selected' : '' }}>
{{ $parent->name }}
</option>
@endforeach
</select>
<h3>子カテゴリ</h3>
<div id="childArea">
@foreach ($childCategoryData as $child)
<label class="articleEditChild" data-parent="{{ $child->parent }}">
<input type="checkbox" name="child[{{ $child->id }}]" value="on"
{{ isset($articleChildData[$child->id]) ? 'checked' : '' }} />{{ $child->name }}
</label>
@endforeach
</div>
<h3>記事本文</h3>
<textarea name="body">{{ $articleData->body ?? '' }}</textarea>
<h3>公開日時</h3>
<input type="text" name="open" value="{{ $articleData->open ?? date('Y/m/d H:i:s') }}" />
<h3>状態</h3>
<div style="margin-bottom: 30px;">
<label><input type="radio" name="private" value="0" {{ ($articleData === null || $articleData->private !== 1) ? 'checked' : '' }} />公開/公開待ち</label>
<label><input type="radio" name="private" value="1" {{ ($articleData !== null && $articleData->private === 1) ? 'checked' : '' }} />非公開</label>
</div>
{{-- CSRFトークン --}}
{{ csrf_field() }}
<input type="button" id="update" value="{{ isset($articleData->id) ? '更新' : '登録' }}" />
</form>
</section>
</article>
<script>
$(document)
.on('click', '#update', function(){
$(this).parents('form').attr('action', '{{ route('admin_article_update') }}').attr('target', '');
$(this).parents('form').submit();
})
;
</script>
@endsection
JavaScript
public/js/admin.js
ページ読み込み時と、親カテゴリを変更した時に、changeArticleEditSubArea()を実行します。
この関数では、子カテゴリ全てを確認し、data-parentの値が親カテゴリIDと一致したら表示するようにしています。
また、非表示にする時にはチェックを外しています。「見えてないけどチェックされている」を防ぐためです。
// ページ読み込み時の処理
$(document).ready(function(){
// 親カテゴリの初期表示にあわせて、子カテゴリの表示を切り替える(記事作成画面のみ)
if ($('#articleEditParent').length > 0) {
changeArticleEditSubArea($('#articleEditParent').val());
}
});
$(document)
.on('change', '#articleEditParent', function() {
// 親カテゴリが変更された際、子カテゴリの表示を切り替える
changeArticleEditSubArea($(this).val());
})
;
/**
* 記事作成画面の時、子カテゴリの表示を親カテゴリにあわせたものにする
*
* @param parentID
*/
function changeArticleEditSubArea(parentID) {
$('.articleEditChild').each(function(){
if ($(this).attr('data-parent') === parentID) {
$(this).css('display', 'inline-block');
} else {
$(this).css('display', 'none');
$('input', this).prop('checked', false).change(); // 非表示にするチェックボックスはチェックを外す
}
});
}
