Laravel dynamic breadcrumbs with links - laravel

I am trying to implement dynamic breadcrumbs in laravel with links. I successfully render the breadcrumbs but without links by following code.
<ol class="breadcrumb">
<li><i class="fa fa-dashboard"></i>Marketplace</li>
#foreach(Request::segments() as $segment)
<li>
{{$segment}}
</li>
#endforeach
</ol>
But now i am facing issue with the urls. I am getting the current url of the route with all the decendents. Can someone please help me that how can I add links to the breadcrumbs ?
Thanks.

If I understand your issue correctly, you just need to fill in the URL of the link. This is untested but I think it should work.
<ol class="breadcrumb">
<li><i class="fa fa-dashboard"></i>Marketplace</li>
<?php $segments = ''; ?>
#foreach(Request::segments() as $segment)
<?php $segments .= '/'.$segment; ?>
<li>
{{$segment}}
</li>
#endforeach
</ol>

This worked for me, tried in Laravel 5.4.*
Requirement for this code to work flawlessly: All URL's should have hierarchy pattern in your routes file
Below code will create crumb for each path -
Home >
<?php $link = "" ?>
#for($i = 1; $i <= count(Request::segments()); $i++)
#if($i < count(Request::segments()) & $i > 0)
<?php $link .= "/" . Request::segment($i); ?>
{{ ucwords(str_replace('-',' ',Request::segment($i)))}} >
#else {{ucwords(str_replace('-',' ',Request::segment($i)))}}
#endif
#endfor
So Breadcrumb for URL your_site.com/abc/lmn/xyz will be - Home > abc > lmn > xyz
Hope this helps!

Im not sure if you already got a solution for this, but i figured out a way to go about it on my project. It might come in handy for your implementation.
I ended up with either adding the whole url to the link or only the segment, which ofc is not desirable, so using array slice i start slicing from the 0 index in the array and only slice untill the current iteration of the loop, then implode the array into a string and then use URL::to to create the link.
<ol class="breadcrumb">
<li>
<i class="fa fa-home"></i>
HOME
</li>
#for($i = 2; $i <= count(Request::segments()); $i++)
<li>
<a href="{{ URL::to( implode( '/', array_slice(Request::segments(), 0 ,$i, true)))}}">
{{strtoupper(Request::segment($i))}}
</a>
</li>
#endfor
</ol>
As you will notice, I only start my iteration from 2 ($i = 2) as my app base url starts at /admin and i manually put my home Url in the first breadcrumb.
Again you might already have a solution, but throught this could work for people who do not want to add the package to get breadcrumbs.

I wrote a this code that can handle laravel resource ( index | edit | create ) routes dynamically:
Custom Breadcrumb => custom.blade.php
#php
$segments=[];
$l=count(Request::segments())-1
#endphp
#switch(Request::segments()[$l])
#case('edit')
#php
$l--;
$segments=array_slice(Request::segments(),0,$l);
$segments[]=$model->slug // Model that passed to this included blade file
#endphp
#break
#default
#php $segments=Request::segments() #endphp
#endswitch
#php
$link=''
#endphp
#foreach($segments as $sg)
#php $link.='/'.$sg #endphp
#if($loop->index<$l)
<li class="breadcrumb-item">
{{ucfirst($sg=='admin'?'home':$sg)}}
</li>
#else
<li class="breadcrumb-item active">
{{ucfirst($sg)}}
</li>
#endif
#endforeach
Use Custom Breadcrumb => example.balde.php
#include('admin.vendor.breadcrumb.custom',['model'=> $articles])

Just add slash / before any link to add decendents to domain name
like that
<a href="/YourLink" ></a>

I liked the solution offered by #rohankhude but it was not showing "/" after the first segment (marketplace). So here is a clean code.
<div class="breadcrumb">
<ul>
<li>
Home
</li>
<?php $link = "" ?>
#for($i = 1; $i <= count(Request::segments()); $i++)
#if($i < count(Request::segments()) & $i > 0)
<?php $link .= "/" . Request::segment($i); ?>
#if ($i == 1)
/ {{ ucwords(str_replace('-',' ',Request::segment($i)))}}
#else
{{ ucwords(str_replace('-',' ',Request::segment($i)))}}
#endif
#else
<a class="active">/ {{ucwords(str_replace('-',' ',Request::segment($i)))}}</a>
#endif
#endfor
</ul>
</div>

Related

How to display default image if no filename exists in Laravel database

I want to display an image for each entry in a list of posts. The name of the images are unique file names. They are all saved in a database (MySQL) table. There is more than one image for each post. The code works right. Except, when there is a post without an image filename. This is a possible scenario but i can't get the code to work. In the event there's no existing filename for a post, i want to display a default filename.
Here's my code:
Images logic:
/**
* Get a vehicle's top or main image data from the image table
*/
public function topImage($id)
{
$image = Vehiclefulldataimage::where('vehiclefulldatas_id', $id)
->orderBy('id', 'ASC')->first();
return $image;
}
Here's the blade view, Posts:
#if (count($posts) > 0)
#foreach($posts as $post)
<?php $imageFilename = (new \App\Models\Logic\Images)->topImage($post->id); ?>
<!--Item-->
<li>
<div class="preview">
#if ($imageFilename = 0)
<img src="{{ asset('images') . '/' . 'defaultImage.jpg' }}" alt="No photo">
#else
<img src="{{ asset('images') . '/' . $imageFilename->disk_image_filename }}" alt="{{ ucfirst($imageFilename->caption) . ' | ' . $post->title }}">
#endif
</div>
<div class="desc">
<h3>{{ str_limit($post->title, 100, '...') }}</h3>
</div>
</li>
<!--/Item-->
#endforeach
#endif
This is the error message i get:
"Trying to get property of Non Object"
Try the following code:
You are using an assignment operator instead of comparison operator
//#if (count($posts) > 0)
#if (!$posts->isEmpty())
#foreach($posts as $post)
<?php $imageFilename = (new \App\Models\Logic\Images)->topImage($post->id); ?>
<!--Item-->
<li>
<div class="preview">
//#if ($imageFilename = 0) this is an assignment operator not comparison operator
#if ($imageFilename->isEmpty())
<img src="{{ asset('images') . '/' . 'defaultImage.jpg' }}" alt="No photo">
#else
<img src="{{ asset('images') . '/' . $imageFilename->disk_image_filename }}" alt="{{ ucfirst($imageFilename->caption) . ' | ' . $post->title }}">
#endif
</div>
<div class="desc">
<h3>{{ str_limit($post->title, 100, '...') }}</h3>
</div>
</li>
<!--/Item-->
#endforeach
#endif
Check your if statement....what you're doing there is an assignment and not a condition test...you can include a column..with a string pointing to the path of your default image..and set it to default...then load it...as default image
All of the answers above fix your problem. However, I recommend you to fix this problem by using Laravel features, Mutators.
https://laravel.com/docs/5.8/eloquent-mutators
Laravel mutators allow you to format or modify your Model attribute.
Just in your Vehiclefulldataimage model write the code below:
public function getImageAttribute($value)
{
//can write more logic here.
return $value ?: 'path/to/your/default/image';
}
Then you don't care more if condition blade template. If your image is empty the mutator returns the default image. So, everywhere when your retrieve Vehiclefulldataimage instance the mutator works properly
Thanks everyone.
After looking at all the answers, i did a simple alteration to my code. I altered:
#if ($imageFilename = 0)
to:
#if ($imageFilename == null)
Thus, my code now looks:
#if (count($posts) > 0)
#foreach($posts as $post)
<?php $imageFilename = (new \App\Models\Logic\Images)->topImage($post->id); ?>
<!--Item-->
<li>
<div class="preview">
#if ($imageFilename == null)
<img src="{{ asset('images') . '/' . 'defaultImage.jpg' }}" alt="No photo">
#else
<img src="{{ asset('images') . '/' . $imageFilename->disk_image_filename }}" alt="{{ ucfirst($imageFilename->caption) . ' | ' . $post->title }}">
#endif
</div>
<div class="desc">
<h3>{{ str_limit($post->title, 100, '...') }}</h3>
</div>
</li>
<!--/Item-->
#endforeach
#endif

modulus with remainder laravel

I am trying to setup columns of 4 from a laravel array which works correctly. The problem is how do you handle remainders? With my loop I end up with 2 extra divs that are empty at the end of my output. I have 10 items that i'm looping over which would give me a remainder of 2.5 Here is my code.
<div class="serviceListingColumn">
<ul>
#foreach($serviceListings as $serviceListing)
#if ($serviceListing->service_category == $services->title)
<li class="serviceListingItem">{{$serviceListing->service_name}}</li>
#endif
#if($loop->iteration % 4 === 0)
</ul>
</div>
<div class="serviceListingColumn">
<ul>
#endif
#endforeach
</ul>
I would suggest chunking the original array into groups, then just looping those. Easier for the template logic.
// Use the Collection's group() functionality in your controller.
// Use collect() if it isn't a Collection already.
$array = collect($array)->chunk(4);
// Your template then doesn't need to worry about modulus,
// and can focus on displaying the chunked groups.
#foreach ($array as $group)
<div class="serviceListingColumn">
<ul>
#foreach ($group as $serviceListing)
<li class="serviceListingItem">{{ $serviceListing->service_name }}</li>
#endforeach
</ul>
</div>
#endforeach

Laravel show all links in paginator

Since Laravel 5.7, the paginator links() method shows only a reduced number of pages when called. The number of links can be customized using the onEachSide($count) method.
‹‹ ‹ 1 2 ... 47 48 49 50 51 52 53 ... 102 103 › ››
I want to display every page in order to make a page selector dropdown, using a html <select>.
Calling onEachSide(9999) does work, but it looks flimsy, and may break on high page counts that the app i'm writing could reach.
What would be the clean way to get all the page links ?
EDIT: I am using a custom view, which looks like the following :
#if ($paginator->hasPages())
<ul class="pagination">
{{-- Previous Page Link --}}
#if ($paginator->onFirstPage())
<li class="disabled">‹‹</li>
<li class="disabled">‹</li>
#else
<li>‹‹</li>
<li>‹</li>
#endif
{{--Pagination Elements --}}
#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"><span>{{ $page }}</span></li>
#else
<li>{{ $page }}</li>
#endif
#endforeach
#endif
#endforeach
{{-- Next Page Link --}}
#if ($paginator->hasMorePages())
<li>›</li>
<li>››</li>
#else
<li class="disabled">›</li>
<li class="disabled"><span>››</li>
#endif
</ul>
#endif
The $elements variable seems to already have the extra pages removed, however.
The paginator uses the bootstrap-4 blade view to render the page. This view always implements the tripple dots.
You could create a custom view that renders all pagination pages without any tripple dot items and pass this view as the first parameter to the links function.
Update: The view you are using is exactly the same as the one build in to Laravel. You shouldn't use the $element variable as this gets windowed with tripple dot elements.
You should use the pagination lastpage variable and loop over all pages yourself. For example, like this:
{{-- Pagination Elements --}}
#for ($page = 1; $page <= $paginator->lastPage(); $page++)
#if ($page == $paginator->currentPage())
<li class="active"><span>{{ $page }}</span></li>
#else
<li>{{ $page }}</li>
#endif
#endforeach

Recursive display of data with blade, laravel

My Controller:
class Comments extends Controller {
public function GenerateComments($id){
$theme = DB::table('New_Themes')
->where('id', $id)
->get();
$Comments = NewTheme_Comment::where('id_theme', $id)->get();
return view('comments', ['Themes'=>$theme, 'Comments'=>$Comments]);
}
My Table(NewTheme_Comment):
id
parent_id
id_theme
user
text
upVotes
downVotes
My view(contains the recursive display of the tree of comments like the same in reddit), ......(data) contains the bootstrap media object, and the </div>'s things are used to round up (visually) the tree of comments as it should be:
<?php
tree($Comments, 0, 0);
$var = -1;
function tree($Comments, $parent_id = 0, $level=0, $c=0) {
global $var;
foreach($Comments as $Comment) {
if($Comment['parent_id'] == $parent_id) {
If ($level > $var) $var++; else {
for ($i = $var-$level+1; $i>0; $i--) { if ($c < 0) echo '</div> </div>'; else $c--; };
$var=$level;
};
echo '........(data)';
tree($Comments, $Comment['id'], $level+1,$c);
};
};
};
?>
The problem is that .........(data) should contain this stuff:
<div class="media">
<div class="media-left">
<img class="media-object" style="height:40px; width:40px;" src="{{ URL::asset("images/upVote.svg") }}" >
<div>{{$Comment->upVotes-$Comment->downVotes}}</div>
<img class="media-object" style="height:40px; width:40px;" src="{{ URL::asset("images/downVote.svg") }}" >
</div>
<div class="media-body">
<p class="media-heading">{{ $Comment->text }}</p>
<p class="media-heading">{{ $Comment->user }} / {{ $Comment->created_at }} </p>
And I am using the blade above this line | , which I can't integrate into that echo in view, replacing the ..........(data).
I have the intuition that the function I should integrate into the controller but I am broken(I spent to much time on recursive method of displaying comments) and I don't know how to take the data and print out it as whole unit recursively.
Any help is GREATLY appreciated to find a way out of this mess, thank you very much
Edit 1:
This is an example if i am filling with bootstrap media object in ........(data):
<div class="media">
<a class="media-left" href="#">
<img class="media-object" src="..." alt="...">
</a>
<div class="media-body">
<h4 class="media-heading">Media heading</h4>
Without 2 x </div>
You are approaching the views in a wrong way, as blade templates are not meant to use functions, it's better to follow the below recommendations.
The best way for that is to place the function code inside a blade file, for example recursive.blade.php:
recursive.blade.php
#foreach($comments as $comment)
//place your code here
#endforeach
Then in your main blade you can call it several times:
main.blade.php
<div>
#include('recursive', ['comments' => $comments])
</div>
The below example works for me and is the most widely used approach. remember the default value for parent_id is -1.
Model
public function children(){
return $this->hasMany(self::class,'parent_id','id')->with('children');
}
Controller
$comments = Comments::where('parent_id','=',-1)->get();
return view('comments',['comments'=> $comments]);
Blade (comments.blade.php)
<div class="tree">
#include('comment-list-widget',['comments' => $comment])
</div>
Blade (comment-list-widget.blade.php)
<ul>
#foreach($comments as $comment)
<li>
<a>{{$comment->text}}</a>
#if(!empty($comment->children) && $comment->children->count())
#include('comment-list-widget',['comments' => $comment->children])
#endif
</li>
#endforeach
</ul>

Drop down menu error-display error

i'm in the middle of creating a website and i want to creat a dynamic dropdown menu.The problem is that when i load the entries from the database only the first entry is displayed correctly , the other entries in the menu are displayed as code. I'm using Xamp with PHP 5.3 and HeidiSql.This is my code :
<div id="1" class="mega solidblocktheme">
<div class="column">
<ul>
<li><a href="<?php include('../conect.php'); $result=mysql_query("SELECT * FROM tours");
while($data=mysql_fetch_row($result))
{ echo $data[2]; ?>"> <?php echo $data[1];
echo "</a></li>"; }
mysql_close($con);?>
</ul>
</div>
</div>
Your loop seems to be in the wrong place. Try something like this:
<ul>
<?php include('../conect.php');
$result=mysql_query("SELECT * FROM tours");
while($data=mysql_fetch_row($result))
{
echo '<li><a href="'.$data[2].'">'.$data[1];
echo "</a></li>";
}
mysql_close($con);?>
</ul>
You should not do it this way .
while($data=mysql_fetch_row($result))
{ echo $data[2]; ?>">
echo ""; }
For every loop , you are just adding content and close tags </a> and </li>
But you are not adding start tags for them .
What you can do is , first store your data result in a string
include('../conect.php');
$result=mysql_query("SELECT * FROM tours");
$data=mysql_fetch_row($result);
mysql_close($con);
$list = "";
foreach($data as $data_key) {
$list.= '<li> '.$data[1].' </li>';
}
So now you got your list
After that comes your HTML , just echo your built string
<div id="1" class="mega solidblocktheme">
<div class="column">
<ul>
<?php
echo $list;
?>
</ul>
</div>
</div>

Resources