How to Create a Database-Driven Multi-Level Navigation Menu Using Laravel

How to create a database-driven multi-level navigation menu using Laravel

So after doing much more searching and reading from different sources this is what I came up with and it's working fine:

/app/models/Navigation.php

<?php

class Navigation extends Eloquent {

/**
* The database table used by the model.
*
* @var string
*/
protected $table = 'navigation';

public function parent() {

return $this->hasOne('navigation', 'id', 'parent_id');

}

public function children() {

return $this->hasMany('navigation', 'parent_id', 'id');

}

public static function tree() {

return static::with(implode('.', array_fill(0, 4, 'children')))->where('parent_id', '=', NULL)->get();

}

}

/app/controllers/HomeController.php

<?php

class HomeController extends BaseController {

protected $layout = "layouts.main";

public function showWelcome()
{

$items = Navigation::tree();

$this->layout->content = View::make('layouts.home.index')->withItems($items);

}

}

/app/views/layouts/home/index.blade.php

<ul>
@foreach($items as $item)
<li>{{ $item->title }}
@foreach($item['children'] as $child)
<li>{{ $child->title }}</li>
@endforeach
</li>
@endforeach
</ul>

Laravel multilevel menus with sorting

Here are the step by step I'm using to get multilevel menus :

Table "menus"

id, title, order, parent_id

Model

class Menu extends Model
{
public function children()
{
return $this->hasMany(self::class , 'parent_id', 'id')->orderBy('order');
}
}

Controller

class MenuController extends Controller
{
public function index()
{
$menus = Menu::where('parent_id', 0)->orderBy('order', 'ASC')->get();
return view('menu', compact('menus'));
}
}

View

@foreach($menus as $menu)
@foreach($menu->children => $child)
<h4>{{ $child->title }}</h4>
@endforeach
@endforeach

How to list select option with multi level categories in Laravel 5

For the ul you can create a recursive function using blade e.g.

@include('partials.menu', $items)

Then in that view something like:

<ul>
{{-- You would have to provide your own logic to decide which class name the ul should have --}}
@foreach($items as $item)

{{ $item->name }}
@if(!empty($item->children)) {{-- Or however you want to check for children --}}
@include('partials.menu', ['items' => $item->children]) {{-- Here I am just telling blade to treat the children as $items where they are passed through --}}
@endif
@endforeach
</ul>

This is a basic implementation of a recursive function with blade.

You can use a similar approach for the select as well.

Hope this helps!

Laravel : Storing navigation in cache but want to set active class based on current url

You may add a new macro in HTML class, simply add this in a file (macros.php) and store it inside app/start directory then include it from the app/startglobal.php file using require/include:

HTML::macro('menuItem', function($name, $title = null, $parameters = array(), $attributes = array()){
$currentUrl = URL::current() == url() ? url('home') : URL::current();
$active = ( $currentUrl == URL::route($name, $parameters) ) ? ' class="active"':'';
return '<li'.$active.'>' . HTML::linkRoute($name, $title, $parameters, $attributes) . '</li>';
});

In your view you may generate the menu items using something like this:

<ul>
{{ HTML::menuItem('page.home', 'Home', array('home')) }}
</ul>

Here page.home is the route name assigned to / when declaring the route and yes in this case routes should have name, for example:

Route::get('/', array('uses' => 'PageController@home', 'as' => 'page.home'));

In the menuItem macro the second parameter (Home) is the menu title to show and the third parameter is an optional parameter if has any. So for example, your About Us page has the parameter about-us and to create the menu item you may use this:

{{ HTML::menuItem('page.about', 'About Us', array('about-us')) }}

This is a possible solution and there may be other ways.

If else statement based on database row

You need to do this in a controller.

Route::get('letters', ['uses' => 'LettersController@index']);

And then in your letters controller

public function index()
{

// Grab letters for the user. You need to be sure that the user is logged in
$letters = Letter::forUser(Auth::user())->get();

$data = [
'letters' => $letters
];

// You will be able to call $letters->count() in your view
return View::make('letters.index', $data);
}

In your letter Model

public function scopeForUser(User $u)
{
return $query->where('user_id', '=', $u->id);
}


Related Topics



Leave a reply



Submit