I am new to laravel blade and I want to have an automatic active navigation bar,
so I have this code
<li>{{ HTML::clever_link("index", 'Home' ) }}</li>
<li><a class="glow" href='breeder'>Breeder's Profile</a></li>
<li><a class="glow" href='gallery'>Gallery</a></li>
<li><a class="glow" href='contact'>Contact Us</a></li>
I used the clever link as I research to do what i want, but it remove the link class "glow" now I want to add the glow class to the li with the clever link, I tried this
<li>{{ HTML::clever_link("index", 'Home', class="glow" ) }}</li>
but it just gives me error. Thanks
You can simply add an argument to your HTML Macro: (Obviously I don't know how your macro looks like so this is just an example)
HTML::macro('clever_link', function($link, $label, $class = ''){
return ''.$label.'';
});
Usage:
{{ HTML::clever_link("index", 'Home', 'glow') }}
Or something a bit more flexible:
HTML::macro('clever_link', function($link, $label, $attributes = array()){
return '<a href="'.$link.'" '.HTML::attributes($attributes).'>'.$label.'</a>';
});
Usage:
{{ HTML::clever_link("index", 'Home', array('class' => 'glow')) }}
(The HTML::attributes() method allows you to convert an array into an HTML attributes string)
// for navigation menu highlight
HTML::macro('clever_link', function($route, $text, $icon) {
if( Request::path() == $route ) {
$active = "class = 'active'";
}
else {
$active = '';
}
return "<a href = '{url($route)}' $active> <i class = '{$icon}'></i>{$text}</a>";
});
</pre>
Usage:
Make your menu as:
{{ HTML::clever_link("/", 'Home', 'icon-home-2') }}
{{ HTML::clever_link("/aboutus", 'About Us', 'icon-dollor') }}
in your menu's link
OR use
https://github.com/pyaesone17/active-state
Related
I am using Lavary's laravel-menu package, and I am trying to build a simple 2 level menu system based on the contents of a db table. I have the middleware created to create the menu on each request:
public function handle($request, Closure $next)
{
Menu::make('NavBar', function($menu){
$menuitems = MenuItem::all();
foreach($menuitems as $menuitem)
{
if(!is_null($menuitem->parent)){
// For example, 'Conferences', a top level menu item with a null parent field
$menu->add($menuitem->title, url($menuitem->url));
}
else{
// Parent is a field in database, for example 'Traverse City 2015' would have the parent 'conferences'
$parent = $menuitem->parent;
$menu->item($parent)->add($menuitem->title, url($menuitem->url));
}
}
});
return $next($request);
}
In my view, I call:
{!! $NavBar->asUl() !!}
I would expect this to render as such:
<ul>
<li>Conferences</li>
<ul>
<li><a href="/conferences/traverse-city-2015">Traverse City 2015</li>
</ul>
</ul>
Instead, it is rendering:
<ul>
<li>Conferences</li>
<li>Traverse City 2015</li>
</ul>
Any ideas why the sub-items aren't showing up correctly?
What you are after is nested groups: https://github.com/lavary/laravel-menu#nested-groups
Menu::make('MyNavBar', function($menu){
$menu->group(array('prefix' => 'pages', 'data-info' => 'test'), function($m){
$m->add('About', 'about');
$m->group(array('prefix' => 'about', 'data-role' => 'navigation'), function($a){
$a->add('Who we are', 'who-we-are?');
$a->add('What we do?', 'what-we-do');
$a->add('Our Goals', 'our-goals');
});
});
});
This will then render as:
<ul>
<li data-info="test">
About
<ul>
<li data-info="test" data-role="navigation"></li>
<li data-info="test" data-role="navigation"></li>
<li data-info="test" data-role="navigation"></li>
</ul>
</li>
</ul>
im trying to implement a view like sphinx documentation where you can click on next and previous to navigate between pages. not sure if im using the custom paginator on array right, i cant get page navigation links to display on a view page. this is the code:
public function paginate($array, $perPage, $pageStart=1) {
$offset = ($pageStart * $perPage) - $perPage;
return new Paginator(array_slice($array, $offset, $perPage, true), $perPage, $pageStart);
}
view()->composer('layouts.book', function($view)
{
//some other code
$pages = [];
foreach($book->textsection_pages as $textsection) {
$pages[] = $textsection->alias;
}
foreach($book->task_pages as $task) {
$pages[] = $task->alias;
}
foreach($book->tutor_pages as $tutor) {
$pages[] = $tutor->alias;
}
foreach($book->eval_pages as $eval) {
$pages[] = $eval->alias;
}
$chapters = $book->chapters()->orderBy('weight', 'asc')->get();
$paginated = $this->paginate($pages, 1);
$view->with(['chapters' => $chapters, 'book' => $book, 'paginated' => $paginated]);
});
and in the view i called {!! $paginated->render() !!}, but no navigation link was displayed.
Here is how I handle custom Pagination in my application (Laravel 5.1). I create a partial view resources/views/partials/pagination.blade.php
#if ($paginator->lastPage() > 1)
<ul id="pagination">
<li>
#if ($paginator->currentPage() > 1)
<a class="prev" href="{{ $paginator->url($paginator->currentPage()-1) }}">Previous</a>
#else
<span class="disabled">Previous</span>
#endif
</li>
<li>
#if ($paginator->currentPage() !== $paginator->lastPage())
<a class="next" href="{{ $paginator->url($paginator->currentPage()+1) }}" >Next</a>
#else
<span class="disabled">Next</span>
#endif
</li>
</ul>
#endif
In my controller, I pass the usual $model->paginate(10) method. Then finally in my view where I want to use the Paginator, resources/views/list.blade.php I do this:
#foreach ($objects as $object)
// Here we list the object properties
#endforeach
#include("partials.pagination", ['paginator' => $objects])
I am fairly new to laravel (L5 specifically) and I am making my own version of a todo app rather than following one of the tutorials out there. I've learned quite a bit so far but the way I have this piece of code currently laid out in my blade template makes me think their might be a simpler way of doing this.
My TodosController#index fn is
public function index()
{
$todos = Todo::get();
return view('todos', compact('todos'));
}
App\Todo extends an Eloquent model which makes data handling very easy!
My route is:
Route::bind('todos', function($slug)
{
return App\Todo::whereSlug($slug)->first();
});
So my page simply displays an unorded list of "todos". I want to have two separate lists. One that is for completed todos and one for incomplete. My blade template looks like this so far and looks a bit messy. Also I am looping over the results twice which is where I think I can improve on.
<h3>Incomplete</h3>
<ul>
#foreach ($todos as $todo)
#if ($todo->completed == 'No')
<li>
{{ $todo->title }}
</li>
#endif
#endforeach
</ul>
<h3>Complete</h3>
<ul>
#foreach ($todos as $todo)
#if ($todo->completed == 'Yes')
<li>
{{ $todo->title }}
</li>
#endif
#endforeach
</ul>
Any suggestions to simplify that blade template?
DRY your code out. You could streamline it by moving the actual item mark-up to a partial template since it’s repeated in both the complete and incomplete lists:
<h3>Incomplete</h3>
<ul>
#foreach ($todos as $todo)
#if ($todo->completed == 'No')
#include('partials.items.todo')
#endif
#endforeach
</ul>
<h3>Complete</h3>
<ul>
#foreach ($todos as $todo)
#if ($todo->completed == 'Yes')
#include('partials.items.todo')
#endif
#endforeach
</ul>
And partials.items.todo would look like this:
<li>
{{ $todo->title }}
</li>
I would also re-factor your loops. Instead of looping over the same list twice, you could split them in your controller:
public function index()
{
$todos = Todo::where('user_id', '=', Auth::id())->get();
$complete = $todos->filter(function ($item) {
return $item->completed = 'Yes';
});
$incomplete = $todos->filter(function ($item) {
return $item->completed = 'No';
});
return view('todos', compact('complete', 'incomplete'));
}
Looking at your Todo model, I’d also make your completed column in the database a boolean field instead of a column containing “Yes” or “No” strings. You could then cast that column value to a proper boolean (since MySQL doesn’t have a native boolean field type):
class Todo extends Model
{
protected $casts = [
'completed' => 'boolean',
];
public function isComplete()
{
return $this->completed;
}
}
And then re-factor your controller action to use this instead:
public function index()
{
$todos = Todo::where('user_id', '=', Auth::id())->get();
$complete = $todos->filter(function ($item) {
return $item->isComplete() === true;
});
$incomplete = $todos->filter(function ($item) {
return $item->isComplete() === false;
});
return view('todos', compact('complete', 'incomplete'));
}
You could even move those collection filters to a custom TodoCollection class:
use Illuminate\Database\Eloquent\Collection as EloquentCollection;
class TodoCollection extends EloquentCollection
{
public function complete()
{
return $this->filter(function ($item) {
return $item->isComplete() === true;
});
}
public function incomplete()
{
return $this->filter(function ($item) {
return $item->isComplete() === false;
});
}
}
Sorry for the lengthy reply, but should give you food for though on how to re-factor your code.
Only a bit simplified but...
You can try in your controller:
public function index()
{
$completed = Todo::where('completed','Yes')->get();
$incompleted = Todo::where('completed','No')->get();
return view('todos', compact('completed', 'incompleted'));
}
in Your template:
<h3>Incomplete</h3>
<ul>
#foreach ($incompleted as $todo)
<li>
{{ $todo->title }}
</li>
#endforeach
</ul>
<h3>Complete</h3>
<ul>
#foreach ($completed as $todo)
<li>
{{ $todo->title }}
</li>
#endforeach
</ul>
Another approach using a subtemplate like this:
//_list_todos.blade.php
#foreach ($todos as $todo)
<li>
{{ $todo->title }}
</li>
#endforeach
And your main template like this:
<h3>Incomplete</h3>
<ul>
#include('_list_todos',['todos'=>$incompleted] )
</ul>
<h3>Complete</h3>
<ul>
#include('_list_todos',['todos'=>$completed] )
</ul>
The advantege to use a subtemplate like the last one is you can reuse the code, and simplify your main templates.
So I'm brand new to symfony (and MVC frameworks in general) so I'll need a complete beginners answer to my question please.
Basically, I've set up a controller to add a class to the navigation element of the current page. At least in theory I have, in practice I get the following exception error:
An exception has been thrown during the rendering of a template ("The controller must return a response (Text elements given).") in "myNewBundle:Page:text-elements.html.twig".
I think that the problem (or at least part of it) is that the controller has been decoupled from the template. So it has no idea if the page it is being called on, is current or not.
Here is the contents of my controller:
<?php
namespace my\NewBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
/**
* #Template("myNewBundle::definitions.html.twig")
*/
class NavController extends Controller
{
public function renderNavAction($target='/usage', $text='Insert Link')
{
$output = '<a href="' . $this->generateUrl($target) . '" ';
if ($this->getRequest()->get('_route') == $target) $output .= 'class="active"';
$output .= '>' . $text . '</a>';
return $output;
}
}
And this is the part of the twig template which should render it out:
<ul>
<li>{{ render(controller('myNewBundle:Nav:renderNav', { 'target': 'my_new_textElements', 'text' : 'Text elements' })) }}</li>
<li>{{ render(controller('myNewBundle:Nav:renderNav', { 'target': 'my_new_buttons', 'text': 'Buttons' })) }}</li>
<li>{{ render(controller('myNewBundle:Nav:renderNav', { 'target': 'my_new_forms', 'text': 'Forms' })) }}</li>
<li>{{ render(controller('myNewBundle:Nav:renderNav', { 'target': 'my_new_lists', 'text': 'Lists' })) }}</li>
<li>{{ render(controller('myNewBundle:Nav:renderNav', { 'target': 'my_new_tables', 'text': 'Tables' })) }}</li>
<li>{{ render(controller('myNewBundle:Nav:renderNav', { 'target': 'my_new_searchBoxes', 'text': 'Search Boxes' })) }}</li>
<li>{{ render(controller('myNewBundle:Nav:renderNav', { 'target': 'my_new_pods', 'text': 'Reusable Pods' })) }}</li>
</ul>
Could somebody please let me know what it is that I'm doing wrong? Note: The template annotations part is something I added when trying to resolve the issue myself. If it's not necessary then I'm happy to remove/alter it.
Read attentively Controller chapter in symfony book. Controller always must return a Response object.
public function renderNavAction($target='/usage', $text='Insert Link')
{
$output = '<a href="' . $this->generateUrl($target) . '" ';
if ($this->getRequest()->get('_route') == $target) $output .= 'class="active"';
$output .= '>' . $text . '</a>';
$response->setContent($output);
$response->setStatusCode(200);
$response->headers->set('Content-Type', 'text/html');
return $response;
}
But in your situation better to make a macro or simply include another template with params.
following simple code:
<li>List</li>
is there a simple way to add an class="active" if the current page matches the _list route?
using the newest PR-Release of symfony2 and twig as template engine
Twig allows for conditionals and the Request object is available throughout the application. If you are including the template, to get the route you want to use:
app.request.attributes.get('_route')
If you are using the render function, you want to use:
app.request.attributes.get('_internal')
With that, you should be able to use:
class="{% if app.request.attributes.get('_route') == '_list' %}active{% endif %}"
or shorter:
class="{{ app.request.get('_route') == '_list' ? 'active' }}"
Sometimes you don't want to do exact matching of a route. For those cases, you can use the "starts with" conditional logic of twig.
As an example, lets assume you are working with books. You have the following routes: book, book_show, book_new, book_edit. You want the navigation item Book to be highlighted for any of those cases. This code would accomplish that.
<a class="{% if app.request.attributes.get('_route') starts with 'book' %}active{% endif %}">Books</a>
<a class="{% if app.request.attributes.get('_route') starts with 'author' %}active{% endif %}">Authors</a>
This example works with at least Symfony 2.3.x
Shortest version:
{% set route = app.request.get('_route') %}
<li class="{{ route starts with 'post' ? 'open' }}"></li>
<li class="{{ route starts with 'category' ? 'open' }}"></li>
Sometimes useful:
{% set route = app.request.get('_route') %}
<li class="{{ 'post' in route ? 'open' }}"></li>
<li class="{{ 'category' in route ? 'open' }}"></li>
With ternary operator:
{% set route = app.request.attributes.get('_route') %}
<ul class="nav navbar-nav">
<li {{ route == 'profile_index' ? 'class="active"' }}><i class="icon-profile position-left"></i> My Profile</li>
<li {{ route == 'influencers_index' ? 'class="active"'}}><i class="icon-crown position-left"></i> Influencers</li>
<li {{ route == 'task_manager_index' ? 'class="active"'}}><i class="icon-alarm-check position-left"></i> Task Manager</li>
</ul>
This is done with symfony 3.4, but probably something similar can be done with SF2.
src\AppBundle\Twig\AppExtension.php
<?php
namespace AppBundle\Twig;
use Symfony\Component\HttpFoundation\RequestStack;
class AppExtension extends \Twig_Extension
{
private $requestStack;
public function __construct(RequestStack $requestStack)
{
$this->requestStack = $requestStack;
}
public function getFunctions()
{
return [
new \Twig_SimpleFunction('activeMenu', [$this, 'activeMenu'])
];
}
/**
* Pass route names. If one of route names matches current route, this function returns
* 'active'
* #param array $routesToCheck
* #return string
*/
public function activeMenu(array $routesToCheck)
{
$currentRoute = $this->requestStack->getCurrentRequest()->get('_route');
foreach ($routesToCheck as $routeToCheck) {
if ($routeToCheck == $currentRoute) {
return 'active';
}
}
return '';
}
}
Add this to services.yml
services:
#... some other services
AppBundle\Twig\AppExtension:
arguments: ["#request_stack"]
Usage:
<ul class="nav navbar-nav">
<li class="{{ activeMenu(['form', 'edit_form']) }}">Form</li>
<li class="{{ activeMenu(['list']) }}">List</li>
</ul>
i found a very good Bundle that handles all this stuff automagically:
https://github.com/KnpLabs/KnpMenuBundle
SF2.2
{{ dump(app.request.server.get('PATH_INFO')) }}
Symfony2.3, in Twig, try this to get uri:
{{ dump(app.request.server.get("REQUEST_URI")) }}
I found more efficient to know if we are on the active page and the link or not:
in file xx.html.twig :
In on your header file
{% set route_name = app.request.attributes.get('_route') %}
And add in html class of twig
{% if route_name matches '{^issue}' %}active{% endif %}
This is how I do it (using Symfony 2.6)
<li {% if app.request.get('_route') == '_homepage' %} class="active" {% endif %}>Student</li>
'_homepage' is the name of route in routing.yml of your bundle and the route looks like this
_homepage:
path: /
defaults: { _controller: CoreBundle:Default:index }
class="class_name {% if loop.index0 == 0 %}CLASSNAME{% endif %}"