やりたいこと
- サブナビを実装したい
- Viewの中にincludeフォルダを作って、共通パーツとして読み込ませる
- 一覧,新規登録,詳細,編集,削除のリンクをつける
- 一覧,新規登録画面では一覧,新規登録だけをリンクに表示
- 詳細,編集,削除画面では上記に加え詳細,編集,削除のリンクを表示
- 自分自身のURLにアクセスした際にはactiveクラスをつける。
- 例えば新規登録にアクセスしたらサブナビの新規登録の部分にactiveクラスがつく。
- 後はそれをCSSで装飾するなりなんなり。Bootstrapならactiveクラスをつけたら色がつくはず。
インクルード方法
ドキュメント見たらわかる話だけど念のため説明
View 「subnavi.blade.php」
パスは views/admin/items/include/subnavi.blade.php とする。
別にディレクトリ名は inc でも includes でもいいけど私はこれにしてます。
<ul>
<li><a href="#">リンク名</a></li>
<li><a href="#">リンク名</a></li>
</ul>
View 「index.blade.php」
パスは views/admin/items/index.blade.php とする
<html>
<head></head>
<body>
<ul>
<li><a href="#">リンク名</a></li>
<li><a href="#">リンク名</a></li>
</ul>
</body>
</html>
↓
<html>
<head></head>
<body>
@include('admin.items.include.subnavi')
</body>
</html>
あとはcreate.blade.phpとかshow.blade.phpとかそういうのにも同じように@includeの記述を書く
失敗例
View 「subnavi.blade.php」
<ul>
<li class="{{ Request::is('admin/items') ? 'active' : '' }}">
<a href="/admin/items">一覧</a>
</li>
<li class="{{ Request::is('admin/items/create') ? 'active' : '' }}">
<a href="/admin/items/create">新規登録</a>
</li>
@if(!empty($item -> id))
<li class="{{ Request::is('admin/items/{{$item -> id}}') ? 'active' : '' }}">
<a href="/admin/items/{{$item -> id}}">詳細</a>
</li>
<li class="{{ Request::is('admin/items/{{$item -> id}}/edit') ? 'active' : '' }}">
<a href="/admin/items/{{$item -> id}}/edit">編集</a>
</li>
<li class="{{ Request::is('admin/items/{{$item -> id}}/delete') ? 'active' : '' }}">
<a href="/admin/items/{{$item -> id}}/delete">削除</a>
</li>
@endif
</ul>
上のコードは動作しない。原因はこれ。
{{ Request::is('admin/items/{{$item -> id}}') ? 'active' : '' }} // これが動かない
{{ Request::is('admin/items/{!!$item -> id!!}') ? 'active' : '' }} // これも動かない
{{ Request::is('admin/items/$item -> id') ? 'active' : '' }} // これも動かない
<?php $id = $item -> id ?>
{{ Request::is('admin/items/$id') ? 'active' : '' }} // 変数に代入しても動かない
// これは動くが、これだとワイルドカードなので期待動作にはならない。編集画面なのに詳細と編集の両方にactiveクラスがつくみたいなのが起きる。
{{ Request::is('admin/items/*') ? 'active' : '' }}
// これは /admin/items/create にアクセスした時に動く。念のため。
{{ Request::is('admin/items/create') ? 'active' : '' }}
何とかして変数を使いたい。。変数というか、数値が可変する部分を表現できたらいいなって
実装
次のようにする。
View 「subnavi.blade.php」
<?php
if( ! function_exists('is_route'))
{
/**
* Alias for Request::is(route(...))
*
* @return mixed
*/
function is_route()
{
$args = func_get_args();
foreach($args as &$arg)
{
if(is_array($arg))
{
$route = array_shift($arg);
$arg = ltrim(route($route, $arg, false), '/');
continue;
}
$arg = ltrim(route($arg, [], false), '/');
}
return call_user_func_array(array(app('request'), 'is'), $args);
}
}
?>
<ul>
<li class="{{ is_route(['admin.items.index']) ? 'active' : '' }}">
<a href="/admin/items">一覧</a>
</li>
<li class="{{ is_route(['admin.items.create']) ? 'active' : '' }}">
<a href="/admin/items/create">新規登録</a>
</li>
@if(!empty($item -> id))
<li class="{{ is_route(['admin.items.show', $item -> id]) ? 'active' : '' }}">
<a href="/admin/items/{{ $item -> id }}">詳細</a>
</li>
<li class="{{ is_route(['admin.items.edit', $item -> id]) ? 'active' : '' }}">
<a href="/admin/items/{{ $item -> id }}/edit">編集</a>
</li>
<li class="{{ is_route(['admin.items.delete', $item -> id]) ? 'active' : '' }}">
<a href="/admin/items/{{ $item -> id }}/delete">削除</a>
</li>
@endif
</ul>
UIKitへの対応について
私の環境はBootstrapじゃなくてUIKitなのでそちらでの記述方法も説明。おとなしくBootstrap使ってくれればいいものを。。
View 「subnavi.blade.php」
<?php
if( ! function_exists('is_route'))
{
/**
* Alias for Request::is(route(...))
*
* @return mixed
*/
function is_route()
{
$args = func_get_args();
foreach($args as &$arg)
{
if(is_array($arg))
{
$route = array_shift($arg);
$arg = ltrim(route($route, $arg, false), '/');
continue;
}
$arg = ltrim(route($arg, [], false), '/');
}
return call_user_func_array(array(app('request'), 'is'), $args);
}
}
?>
<div class="uk-margin uk-grid">
<div class="uk-width-medium-1-1">
<div>
<ul class="uk-tab">
<li class="{{ is_route(['admin.items.index']) ? 'uk-active' : '' }}">
<a href="/admin/items">一覧</a>
</li>
<li class="{{ is_route(['admin.items.create']) ? 'uk-active' : '' }}">
<a href="/admin/items/create">新規登録</a>
</li>
@if(!empty($item -> id))
<li class="{{ is_route(['admin.items.show', $item -> id]) ? 'uk-active' : '' }}">
<a href="/admin/items/{{ $item -> id }}">詳細</a>
</li>
<li class="{{ is_route(['admin.items.edit', $item -> id]) ? 'uk-active' : '' }}">
<a href="/admin/items/{{ $item -> id }}/edit">編集</a>
</li>
<li class="{{ is_route(['admin.items.delete', $item -> id]) ? 'uk-active' : '' }}">
<a href="/admin/items/{{ $item -> id }}/delete">削除</a>
</li>
@endif
</ul>
</div>
</div>
</div>
エラーが起きるんですけど
Route [admin.items.delete] not defined. とか出る場合。
ルーティング時にNameをつけ忘れていることが原因。
以下のコードで調べる
php artisan route:list
+--------+-----------+--------------------------+---------------------+----------------------------------------------------+------------+
| Domain | Method | URI | Name | Action | Middleware |
+--------+-----------+--------------------------+---------------------+----------------------------------------------------+------------+
| | POST | admin/items | admin.items.store | App\Http\Controllers\Admin\ItemsController@store | web |
| | GET|HEAD | admin/items | admin.items.index | App\Http\Controllers\Admin\ItemsController@index | web |
| | GET|HEAD | admin/items/create | admin.items.create | App\Http\Controllers\Admin\ItemsController@create | web |
| | GET|HEAD | admin/items/{id}/delete | | App\Http\Controllers\Admin\ItemsController@delete | web |
| | DELETE | admin/items/{id}/delete | | App\Http\Controllers\Admin\ItemsController@destroy | web |
| | DELETE | admin/items/{items} | admin.items.destroy | App\Http\Controllers\Admin\ItemsController@destroy | web |
| | GET|HEAD | admin/items/{items} | admin.items.show | App\Http\Controllers\Admin\ItemsController@show | web |
| | PUT|PATCH | admin/items/{items} | admin.items.update | App\Http\Controllers\Admin\ItemsController@update | web |
| | GET|HEAD | admin/items/{items}/edit | admin.items.edit | App\Http\Controllers\Admin\ItemsController@edit | web |
+--------+-----------+--------------------------+---------------------+----------------------------------------------------+------------+
deleteのネームルーティングができてなかった
app/routes.php
<?php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/
Route::get('/admin/items', function () {
return view('.admin.items.index');
});
Route::resource('/admin/items', 'Admin\\ItemsController');
Route::get('/admin/items/{id}/delete','Admin\\ItemsController@delete');
Route::delete('/admin/items/{id}/delete','Admin\\ItemsController@destroy');
次のように修正
<?php
/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/
Route::get('/admin/items', function () {
return view('.admin.items.index');
});
Route::resource('/admin/items', 'Admin\\ItemsController');
Route::get('/admin/items/{id}/delete','Admin\\ItemsController@delete')->name('admin.items.delete');
Route::delete('/admin/items/{id}/delete','Admin\\ItemsController@destroy')->name('admin.items.destroy');
これで動くはず。動かなかったら知らない。ごめん。
改善
nunulk 様から頂いた非常にナイスな書き方を受けて改善。
そうだね、「 . 」で追加すりゃよかったね…危うく読解不能な謎コードを錬成するところでした。危ない危ない。
Bootstrapの場合
の記述は全て削除してくださいView 「subnavi.blade.php」
<ul>
<li class="{{ Request::is('admin/items') ? 'active' : '' }}">
<a href="/admin/items">一覧</a>
</li>
<li class="{{ Request::is('admin/items/create') ? 'active' : '' }}">
<a href="/admin/items/create">新規登録</a>
</li>
@if(!empty($item -> id))
<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id) ? 'active' : '' }}">
<a href="/admin/items/{{ $item -> id }}">詳細</a>
</li>
<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id . '/edit') ? 'active' : '' }}">
<a href="/admin/items/{{ $item -> id }}/edit">編集</a>
</li>
<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id . '/delete') ? 'active' : '' }}">
<a href="/admin/items/{{ $item -> id }}/delete">削除</a>
</li>
@endif
</ul>
UIKitの場合
の記述は全て削除してくださいView 「subnavi.blade.php」
<div class="uk-margin uk-grid">
<div class="uk-width-medium-1-1">
<div>
<ul class="uk-tab">
<li class="{{ Request::is('admin/items') ? 'uk-active' : '' }}">
<a href="/admin/items">一覧</a>
</li>
<li class="{{ Request::is('admin/items/create') ? 'uk-active' : '' }}">
<a href="/admin/items/create">新規登録</a>
</li>
@if(!empty($item -> id))
<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id) ? 'uk-active' : '' }}">
<a href="/admin/items/{{ $item -> id }}">詳細</a>
</li>
<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id . '/edit') ? 'uk-active' : '' }}">
<a href="/admin/items/{{ $item -> id }}/edit">編集</a>
</li>
<li class="{{ isset($item->id) && Request::is('admin/items/' . $item->id . '/delete') ? 'uk-active' : '' }}">
<a href="/admin/items/{{ $item -> id }}/delete">削除</a>
</li>
@endif
</ul>
</div>
</div>
</div>