Refactor to show link or not in blade - php

I felt this code look a bit messy, the logic is to show a link <a href or otherwise show text only.
How can I refactor this to look cleaner and maintainable?
<ol class="breadcrumb">
<li class="{{ $active == 'sign_in'? 'active':'' }}">
#if($active != 'sign_in')
#php($showLink = true)
#else
#php($showLink = false)
#endif
#if($showLink)
<a href="{{ url_secure('sign_in') }}">
#endif
Sign In
#if($showLink)
</a>
#endif
</li>
<li class="{{ $active == 'article'? 'active':'' }}">
#if($active != 'article' && $showLink)
#php($showLink= true)
#else
#php($showLink= false)
#endif
#if($showLink)
<a href="{{ url_secure('article')}}">
#endif
Articles
#if($showLink)</a>#endif
</li>
<li> </li> //repeat the code logic like above
</ol>
It would be good if there a way to reduce if conditions and use loop.

Why not just:
<li class="{{ $active == 'sign_in'? 'active':'' }}">
#if ($active != 'sign_in')
Sign In
#else
Sign In
#endif
</li>
Also it is unclear why you check $showLink that was set previoulsy.
Okay, as I've read your comments, I've modified template a bit with using foreach loop:
#php
// some initial variables
$allowed_to_click = true;
// this is a link to selected page
$selected_link = 'something';
#endphp
#foreach ($links as $link)
#php
// check if this link is ACTIVE
$active = $link == $selected_link;
// check if we can CLICK this link
$allowed_to_click = $active || $allowed_to_click;
#endphp
<li class="{{ $active ? 'active':'' }}">
#if ($allowed_to_click)
Some Caption
#else
Some Caption
#endif
</li>
#php
// if link is ACTIVE - following links are unclickable
if ($active) {
$allowed_to_click = false;
}
#endphp
#endforeach

Related

When using the blade structure in Laravel 9, I get the error "Undefined variable $__env"

There is no problem when I get php's own tags instead of '#' tags. Can anyone make sense of this?
<?php function buildCategory($parent, $category){ ?>
#isset($category['parent_cats'][$parent])
<ul>
#foreach ($category['parent_cats'][$parent] as $cat_id)
#foreach ($category['userPagePerms'] as $userPagePerm)
#if (!isset($category['parent_cats'][$cat_id]))
<li data-jstree='{"selected":{{ ($userPagePerm->backend_page_permission_id == $cat_id) ? 'true' : 'false' }},"opened":true}'>
<a href='{{$category['categories'][$cat_id]->id }}'> {{ $category['categories'][$cat_id]->name}}</a>
</li>
#endif
#if (isset($category['parent_cats'][$cat_id]))
<li data-jstree='{"selected":{{ ($userPagePerm->backend_page_permission_id == $cat_id) ? 'true' : 'false' }},"opened":true}'>
<a href='{{ $category['categories'][$cat_id]->id }}'>{{$category['categories'][$cat_id]->name }}</a>
<?php buildCategory($cat_id, $category); ?>
</li>
#endif
#endforeach
#endforeach
</ul>
#endisset
<?php } buildCategory(0, $category); ?>
It worked when using PHP's own tags. I would expect it to work with the '#' tag.
The code snippet I was able to run. Only the foreach part is the problem.
<?php foreach ($category['parent_cats'][$parent] as $cat_id) {
<?php foreach ($category['userPagePerms'] as $userPagePerm) { ?>
Error ss : enter image description here

How do I customize the pagination items in this Laravel 8 application?

I am working on a blogging application in Laravel 8.
The ArticlesController controller I have this method to display the paginated articles:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\ArticleCategory;
use App\Models\Article;
use App\Models\Comment;
class ArticlesController extends FrontendController {
// Articles per page
protected $per_page = 12;
public function index(Request $request) {
// Search query
$qry = $request->input('search');
$articlesQuery = Article::where('title', 'like', '%' . $qry . '%')
->orWhere('short_description', 'like', '%' . $qry . '%')
->orWhere('content', 'like', '%' . $qry . '%');
// Search results count
if ($qry) {
$article_count = $articlesQuery->count();
}
$articles = $articlesQuery->orderBy('id', 'desc')->paginate($this->per_page);
$featured_articles = Article::where('featured', 1)->orderBy('id', 'desc')->get();
return view('themes/' . $this->theme_directory . '/templates/index',
array_merge($this->data, [
'search_query' => $qry,
'articles' => $articles,
'featured_articles' => $featured_articles,
'article_count' => $article_count ?? null
])
);
}
}
The pagination, in the plain HTML template, looks like this:
<nav class="pgn">
<ul>
<li>
<a class="pgn__prev" href="#0">Prev</a>
</li>
<li><a class="pgn__num" href="#0">1</a></li>
<li><span class="pgn__num current">2</span></li>
<li><a class="pgn__num" href="#0">3</a></li>
<li><span class="pgn__num dots">…</span></li>
<li><a class="pgn__num" href="#0">4</a></li>
<li>
<a class="pgn__next" href="#0">Next</a>
</li>
</ul>
</nav>
The goal
The goal is to keep the pagination structure above, in Laravel's Blade.
The problem
The code below works for the "Next" and "Prev" buttons, but not the links in between.
<nav class="pgn">
<ul>
<li>
<a class="pgn__prev" href="{{ $articles->withQueryString()->previousPageUrl() }}">Prev</a>
</li>
{!! $articles->withQueryString()->links() !!}
<li>
<a class="pgn__next" href="{{ $articles->withQueryString()->nextPageUrl() }}">Next</a>
</li>
</ul>
</nav>
Questions
What causes this bug?
What is the easiest fix?
To create a custom pagination, I'd recommend to make use of a custom "view".
Basically, what would you have to do (which you have already done), is define a limit, and then basically do the following:
you create your view file (which will be the custom paginator) - name it however you want to name it. I'll name it custom.blade.php
This view has to be created after running the command: php artisan vendor:publish --tag=laravel-pagination
here you can find a bit more in the documentation about it: https://laravel.com/docs/9.x/pagination#customizing-the-pagination-view
#if ($paginator->onFirstPage())
<li class="disabled"><span>← Previous</span></li>
#else
<li>
<a class="pgn__prev" href="{{ $articles->withQueryString()->previousPageUrl() }}">Prev</a>
</li>
#endif
#foreach ($elements as $element)
#if (is_string($element))
<li class="disabled"><span>{{ $element }}</span></li>
#endif
#if (is_array($element))
#foreach ($element as $page => $url)
#if ($page == $paginator->currentPage())
<li class="active my-active"><span>{{ $page }}</span></li>
#else
<li>{{ $page }}</li>
#endif
#endforeach
#endif
#endforeach
#if ($paginator->hasMorePages())
<li>
<a class="pgn__next" href="{{ $articles->withQueryString()->nextPageUrl() }}">Next</a>
</li>
#else
<li class="disabled"><span>Next</span></li>
#endif
And finally, on the view where you want to make use of the custom pagination:
{{ $articles->links(‘path.pagination.custom') }}
(just make sure to have the correct path)
edit: It's a bit hard for me to give a definitive answer without looking at the project itself, but I hope this at least helps somehow.

Laravel Pagination "Three Dots" Separator customization

Im currently using Laravel 5.3 and was wondering if there is a option for the customization of the Three Dots deperator. (skips page 9-10, which is to late)
Example
Currently the Three dots initiate if there are more than 11 pages... Which isnt quiet useful if your site is responsive. if there are to many pages so it breaks into 2 lines.
Example2
I cannot find anything regarding there being options for $resource->links(). But if there is please tell me! Much appreciated.
Edit: it has to do with the following function:
vendor/laravel/framework/src/Illuminate/Pagination/LengthAwarePaginator.php (page: 128, render()). The current function does not support a second variable. So i guess i have to rebuild it?
This is a solution for Laravel 5.5+. Here is what it does:
Shows the first and the last page.
Shows previous and next two pages from the current page.
Three dots only appear on the left after the current page is greater than 4.
Three dots only appear on the right after the current page is less than the 4 - (count of pages).
<!-- Pagination Elements -->
#foreach ($elements as $element)
<!-- Array Of Links -->
#foreach ($element as $page => $url)
<!-- Use three dots when current page is greater than 4. -->
#if ($paginator->currentPage() > 4 && $page === 2)
<li class="page-item disabled"><span class="page-link">...</span></li>
#endif
<!-- Show active page else show the first and last two pages from current page. -->
#if ($page == $paginator->currentPage())
<li class="page-item active"><span class="page-link">{{ $page }}</span></li>
#elseif ($page === $paginator->currentPage() + 1 || $page === $paginator->currentPage() + 2 || $page === $paginator->currentPage() - 1 || $page === $paginator->currentPage() - 2 || $page === $paginator->lastPage() || $page === 1)
<li class="page-item"><a class="page-link" href="{{ $url }}">{{ $page }}</a></li>
#endif
<!-- Use three dots when current page is away from end. -->
#if ($paginator->currentPage() < $paginator->lastPage() - 3 && $page === $paginator->lastPage() - 1)
<li class="page-item disabled"><span class="page-link">...</span></li>
#endif
#endforeach
#endforeach
Output:
Page 1 (first page)
Page 3
Page 10 (last page)
Option 1 :
You can customize default files but don't change vendor files directly. Publish them and then add modifications to that.
php artisan vendor:publish --tag=laravel-pagination
This command will automatically create the folder /resources/views/vendor/pagination and you have your files for modification.
You can get more information here : laravel pagination
Option 2:
Maybe you want to get rid of the files that are generated by default. Or, perhaps you want to assign another file to be responsible for your default pagination view.
All of this is possible, but you will need to inform the AppServiceProvider for this action by calling the new pagination views in the boot() method:
use Illuminate\Pagination\Paginator;
public function boot(){
Paginator::defaultView('your-pagination-view-file-name');
Paginator::defaultSimpleView('your-pagination-view-file-name');
}
Get information for defaultView and defaultSimpleView here :laravel pagination
I have created new file for pagination and added in AppServiceProvider.
#if ($paginator->hasPages())
<ul class="blog-pagenation">
{{-- Previous Page Link --}}
#if ($paginator->onFirstPage())
<li class="disabled"><a>«</a></li>
#else
<li>«</li>
#endif
#if($paginator->currentPage() > 3)
<li class="hidden-xs">1</li>
#endif
#if($paginator->currentPage() > 4)
<li><a>...</a></li>
#endif
#foreach(range(1, $paginator->lastPage()) as $i)
#if($i >= $paginator->currentPage() - 2 && $i <= $paginator->currentPage() + 2)
#if ($i == $paginator->currentPage())
<li class="active"><a class="active">{{ $i }}</a></li>
#else
<li>{{ $i }}</li>
#endif
#endif
#endforeach
#if($paginator->currentPage() < $paginator->lastPage() - 3)
<li><a>...</a></li>
#endif
#if($paginator->currentPage() < $paginator->lastPage() - 2)
<li class="hidden-xs">{{ $paginator->lastPage() }}</li>
#endif
{{-- Next Page Link --}}
#if ($paginator->hasMorePages())
<li>»</li>
#else
<li class="disabled"><a>»</a></li>
#endif
</ul>
#endif
By using this i am able to get 3 dots in starting and ending you have to customize classes based on your themes.
Adding to the previous response, once you generate the vendor view files with the artisan command php artisan vendor:publish you can create a new one in that folder and call it for example custom.blade.php and put the following code:
#if ($paginator->hasPages())
<ul class="custom-pagination">
{{-- Previous Page Link --}}
#if ($paginator->onFirstPage())
<li class="disabled pageNumber"><span>« Prev</span></li>
#else
<li><a class="pageNumber" href="{{ $paginator->previousPageUrl() }}" rel="prev">«</a></li>
#endif
{{-- Pagination Elements --}}
#foreach ($elements as $element)
{{-- Array Of Links --}}
#if (is_array($element))
#foreach ($element as $page => $url)
#if ($page === $paginator->currentPage())
<li class="active pageNumber"><span>{{ $page }}</span></li>
#elseif (($page === $paginator->currentPage() + 1 || $page === $paginator->currentPage() + 2)
|| $page === $paginator->lastPage())
<li><a class="pageNumber" href="{{ $url }}">{{ $page }}</a></li>
#elseif ($page === $paginator->lastPage()-1)
<li class="disabled"><span>...</span></li>
#endif
#endforeach
#endif
#endforeach
{{-- Next Page Link --}}
#if ($paginator->hasMorePages())
<li><a class="pageNumber" href="{{ $paginator->nextPageUrl() }}" rel="next">Next »</a></li>
#else
<li class="disabled pageNumber"><span>Next »</span></li>
#endif
</ul>#endif
The important part of the code for the three dots is in the {{-- Array Of Links --}} portion. I think this more or less does what you need but may require additional tweaking.
then you can use it in your view like this:
<div class="pagination">
#if ($users instanceof \Illuminate\Pagination\LengthAwarePaginator)
{{ $users->links('vendor.pagination.custom') }}
#endif
</div>

How to make menu and submenu dynamic Laravel

I want to make menu and submenu dynamic .I made menu with their link but unable to make submenu,please help me my database structure
table name:menu
id menu_name url timestamps
table:sub_menu
id submenu_name link menu_id timestamps
my query is like this
public function menu()
{
$sql=\DB::table('menu')->rightjoin('sub_menu','menu.id','=','sub_menu.menu_id')
->select('submenu_name','link','url','menu_id','menu_name','menu.id')->get();
return view('products.show.menu',compact('sql'));
}
view
<ul>
#foreach($sql as $key => $nav)
#if($key > 0)
<li>
{{$nav->menu_name}}
#if (count($nav->submenu_name) > 0 )
<ul>
#foreach($nav->submenu_name as $child)
<li>{{$child->submenu_name}}</li>
#endforeach
#endif
</ul>
</li>
#endif
#endforeach
</ul>
Have you set up models for these tables? Your query will return multiple rows for each menu/submenu combination, meaning you can't just iterate over it as you are. There's no need to use the query builder here.
Assuming your models are set up as follows (you will need to check the namespace used in the relationships):
class Menu extends Eloquent
{
protected $table = 'menu';
public function submenu()
{
return $this->hasMany('App\SubMenu');
}
}
class SubMenu extends Eloquent
{
protected $table = 'sub_menu';
public function menu()
{
return $this->belongsTo('App\Menu');
}
}
In your controller, you can do:
public function menu()
{
$menu = Menu::with('submenu')->get();
return view('products.show.menu', compact('menu'));
}
Then in your view:
<ul>
#foreach($menu as $menuItem)
<li>
{{ $menuItem->menu_name }}
#if( ! $menuItem->submenu->isEmpty())
<ul>
#foreach($menuItem->submenu as $subMenuItem)
<li>{{ $subMenuItem->submenu_name }}</li>
#endforeach
</ul>
#endif
</li>
#endforeach
</ul>
You can use it without controller
`#foreach(App\Menu::get() as $menuItem)
#if( ! $menuItem->submenu->isEmpty() )
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
{{ $menuItem->menu_name }}
</a>
#else
<li>
{{ $menuItem->menu_name }}
#endif
#if( ! $menuItem->submenu->isEmpty())
<ul class="dropdown-menu" role="menu">
#foreach($menuItem->submenu as $subMenuItem)
<li>{{ $subMenuItem->submenu_name }}</li>
#endforeach
</ul>
#endif
</li>
#endforeach`

Setting Bootstrap navbar active class in Laravel 5

I've been wondering around looking for solutions, but can't really understand especially when creating helpers. I'm new in Laravel and I want a simple or if not a detailed instruction on how to set the active class for my bootstrap navbar.
Here's what I've done so far, but can't get it done:
<div class="header clearfix">
<nav>
<ul class="nav nav-pills pull-right">
<li class="">Home
</li>
<li {{ Request::is('about*') ? ' class="active"' : null }}>About Us
</li>
<li>Login
</li>
</ul>
</nav>
<h2 class="">Tobacco Prevention and Control Program</h2>
</div>
EDIT
Setting class="active" will make all nav-pills active. The intended effect is that only the li of the current page have the active class.
If you are working with named routes. You can use this approach in your views:
{{ Route::currentRouteNamed('about') ? 'active' : '' }}
or
{{ Route::is('about') ? 'active' : '' }}
The Illuminate\Routing\Router#is(...) is an alias of the Illuminate\Routing\Router#currentRouteNamed(...).
Your code is working fine, but you have to use it for every link that can be active. It is better to return only class name, not class="..." so you can add other classes.
Be careful when using * at the end (about*). If you use /* for home page then it will always be marked as active (because every other page starts with /).
<ul class="nav nav-pills pull-right">
<li class="{{ Request::is('/') ? 'active' : '' }}">
Home
</li>
<li class="{{ Request::is('about') ? 'active' : '' }}">
About Us
</li>
<li class="{{ Request::is('auth/login') ? 'active' : '' }}">
Login
</li>
</ul>
You can also move {{ Request::is('/') ? 'active' : '' }} to helper function/method.
<ul class="nav nav-second-level">
<li class="{{ Request::segment(1) === 'programs' ? 'active' : null }}">
<a href="{{ url('programs' )}}" ></i> Programs</a>
</li>
<li class="{{ Request::segment(1) === 'beneficiaries' ? 'active' : null }}">
Beneficiaries
</li>
<li class="{{ Request::segment(1) === 'indicators' ? 'active' : null }}">
Indicators
</li>
</ul>
Throw this in your helper.php
function set_active($path, $active = 'active') {
return call_user_func_array('Request::is', (array)$path) ? $active : '';
}
Use it like so
<li class="{{ set_active(['about*']) }}">About Us
You can pass a single string to a route or multiple and wildcards.
See more detail on Laravel Trick
Set a section on your blade file (let home.blade.php) like
#section('Home', 'my-active-class')
And set a section on your another blade file (let about.blade.php) like
#section('About', 'my-active-class')
and yield this section on app.blade.php (Suppose you are extending from app.blade.php)
...
<li class="#yield('Home')">Home</li>
<li class="#yield('About')">About</li>
...
Request::path() returns the request uri, for example: http://localhost/programs , will return programs, so you can do this:
<li class="{{ Request::path() == 'programs' ? 'active' : '' }}">
</i> Programs
</li>
solution is
<ul class="nav navbar-nav pull-right">
<li class="{{ Request::is('/') ? 'active' : '' }}">
Home
</li>
<li class="{{ Request::is('about') ? 'active' : '' }}">
About Us
</li>
<li class="{{ Request::is('whyus') ? 'active' : '' }}">
Why Us
</li>
</ul>
This is simple: to get your links to be active when using bootstrap, all you need is an if statement inside the class link, for instance: i have my current url as http://example.com/home
<li class="{{ Request::url() == url('/home') ? 'active' : '' }}"><a href="/home" ></li>
Home
</a>
and you are good to go.
The solution given by #Daniel Antos is best answer, as I have found. Mr. Danial Antos also warned about using * at the end (about*). Because while using /* for home page then it is always marked as active (because every other page starts with /). So, I have used as follows and it worked fine for me:
{{ (Request::is('users') || Request::is('users/*') ? 'active open' : '') }}
I think this would be simple, and it works for me.
<li class="{{ Request::segment(1)=='vehicles' ? 'active' : '' }}">
Vehicles
</li>
I found the solution:
composer require devmarketer/easynav
More details : https://github.com/DevMarketer/LaravelEasyNav
use
Request::is('[level]') ? 'active' : ''
In case of multilevel, use:
Request::is('[level]', '[level]/*') ? 'active' : ''
<ul class="nav nav-second-level">
<li class={{ Request::is('/') ? 'active' : '' }}>
<a href="{{ url('programs' )}}" ></i> Programs</a>
</li>
<li class="{{ Request::segment(1) === 'beneficiaries' ? 'active' : null }}">
Beneficiaries
</li>
<li class="{{ Request::segment(1) === 'indicators' ? 'active' : null }}">
Indicators
</li>
</ul>
The Easiest way is to add class active :-
#if (request()->routeIs('dashboard'))
class="active"
#endif
If we manage to get the URL path, we can compare it with the routes and put an active class there.
{{'/'==request()->path()?'active':''}}
{{'about'==request()->path()?'active':''}}
I have created a simple but fun and easy to use package named Active which can solve your problem and maybe more...
I will be glad to see your comments.
Link of the package:
https://github.com/tuytoosh/active

Categories