I want to get my navigation from an array and show an active class if the page is active. Everything is working but i don't get how i can make the page active with the class. Here is a little bit of my code:
foreach($navlinks as $key => $value){
if ($value === $key){
echo '<li class="active">'.$value.'';
}else {
echo '<li>' . $value . '';
}
}
Can anybody help me with this?
Thank you very much
EDIT:
My Array:
$navlinks = array ('index' => 'Home', 'over-ons' => 'Over ons', 'contact' => 'Contact');
EXAMPLE:
<li class="active">Contact</li>
Your code is almost there. You just need to fix the comparison to determine the current page. You may need to do something like
$current_page = substr($_SERVER['REQUEST_URI'], 1); // trim off the leading slash
$current_page = str_replace('.php', '', $current_page); // trim off the extension
foreach ($navlinks as $key => $value) {
if ( $current_page == $key ) {
...
}
else {
...
}
}
I do not want to turn to jQuery for this solution. I just want to select the parent $key of the active $value in the php array so that when the sub menu tab is active, the parent tab is active too.
Example: In the array below, the Engineer key has an array within it to specify the sub pages that drop down beneath that tab in the menu. When one of these sub pages is selected, how can I make the parent tab active by climbing the array to get the $key of the $value that is selected?
I'm using url parameters and not directories. The only directory being used is /jobs/ and the url parameters are ?position=.
A full url will look like:
http://computerhelpwanted.com/jobs/?position=Software+Engineer
So I have already figured out how to set sub menu tabs active, now I just need to set top level tabs active when its sub menu tab is active.
I'll be adding another condition to this statement in the example code below.
if (strpos($position,$filename) !== false) {
$attr_current = ' class="current"';
} else {
$attr_current = '';
}
It only works partially the way it is with the if (strpos($position,$filename) !== false) condition, however this won't always be true. Sometimes $position will not be in $filename and in this case I need an alternative solution. Preferably by just including a condition that says (when $value is selected, also select the parent $key)
Array:
// Menu Items
$li_1 = 'Engineer';
$pages = array(
// Engineer
$li_1 => array(
'pageTitle' => $li_1,
'subpages' => array(
'Software '.$li_1 => 'Software',
'Embedded Software '.$li_1 => 'Embedded Software',
'Computer '.$li_1 => 'Computer',
'Systems-'.$li_1 => 'Systems',
'Graphics '.$li_1 => 'Graphics',
'Research Development '.$li_1 => 'R&D',
'Network '.$li_1 => 'Network',
'Network Security '.$li_1 => 'Network Security',
'Technical Support '.$li_1 => 'Technical Support',
)
),
);
Dynamic menu list:
<? foreach ($pages as $filename => $value) {
if (is_array ($value)) {
$href = '#menu';
$pageTitle = $value ['pageTitle'];
} else {
$href = $dir_structure.$filename;
$pageTitle = $value;
}
if (strpos($position,$filename) !== false || $value == $currentPage) {
$attr_current = ' class="current"';
} else {
$attr_current = '';
}
echo '
<li'.$attr_current.'>'.$pageTitle.'';
if (is_array ($value)) {
echo '
<ul class="subMenu">';
foreach ($value ['subpages'] as $subfilename => $subpageTitle) {
if ($subfilename == $position) {
$attr_current = ' class="current"';
} else {
$attr_current = '';
}
echo '
<li'.$attr_current.'>'.$subpageTitle.'</li>';
} // foreach subpages
echo '
</ul>';
} // is_array
echo '
</li>';
} // foreach pages
Trying to construct a navigation using multi-dimensional arrays and recursion. I have the following code:
First I run <?php $title = 'pagename'; ?> on each individual page beneath doctype (for active class detection)
ARRAY:
<?php
$nav_array = array ('Home' => 'index.php',
'About' => array ( 'about.php', array (
'Michael' => array( 'michael.php', array (
'Blog' => 'blog.php',
'Portfolio' => 'portfolio.php')),
'Aaron' => 'aaron.php' ,
'Kenny' => 'kenny.php',
'David'=> 'david.php')),
'Services' => array ( 'services.php', array (
'Get Noticed' => 'getnoticed.php',
'Hosting' => 'hosting.php')),
'Clients' => 'clients.php',
'Contact Us' => 'contact.php'
);
$base = basename($_SERVER['PHP_SELF']);
?>
FOREACH: (generates nav)
<ul>
<?php
foreach ($nav_array as $k => $v) {
echo buildLinks ($k, $v, $base);
}
?>
</ul>
buildLinks:
<?php // Building the links
function buildLinks ($label_name, $file_name, $active_class) {
if ($label_name == $title) {
$theLink = "<li><a class=\"selected\" href=\"$file_name\">$label_name</a></li>\n";
} else {
$theLink = "<li>$label_name</li>\n";
}
return $theLink;
}
?>
Result: http://khill.mhostiuckproductions.com/siteLSSBoilerPlate/arraytest.php
The sub menu's will appear on the hover of parent element using CSS. I need to be able to fall through multiple sub-levels without modifying anything but the array.
How do I make my foreach fall through the rest of the array recursively?
(Note: that I have to have the ability to apply a class of active to current pages, and a class of arrow to parent elements that have a sub-menu present.)
No matter what data structure you use to build your navigation, you'll need to make your function recursive, here's a quick and dirty way:
echo "<ul>";
foreach ($nav_array as $nav_title => $nav_data) {
echo buildLinks($nav_title, $nav_data, $base, $title);
}
echo "</ul>";
/* NOTE that we pass $title to the function */
function buildLinks ($label_name, $file_name, $active_class, $title) {
$theLink = '';
/* this is dirty code, you should reconsider your data structure */
$navigation_list = false;
if (is_array($file_name)) {
$navigation_list = $file_name[1];
$file_name = $file_name[0];
}
if ($active_class == $title) {
$theLink = "<li><a class=\"selected\" href=\"$file_name\">$label_name</a></li>\n";
} else {
$theLink = "<li>$label_name</li>\n";
}
if ($navigation_list) {
$theLink .= "<ul>";
foreach ($navigation_list as $nav_title => $nav_data) {
$theLink .= buildLinks($nav_title, $nav_data, $active_class, $title);
}
$theLink .= "</ul>";
}
return $theLink;
}
Not a clean solution in anyway, if I were you I'd change the data structure to be an easier one to handle.
I think this is a very bad way. I recommend to save your menu elements as XML or JSON and use parsers. It will facilitate your work.
Hi I am trying to echo out check boxes, and then determine if they are checked in my controller and add them to an array if they are. I have followed a guide from SO but still having issues. Any insight much appreciated!
Controller Code:
foreach ($content['options'] as $option) {
$id = $option['id'];
$checked = (isset($_POST[$id])) ? true : false;
if ($checked == TRUE) {
array_push($recipientGroups, $id);
}
}
View Code:
foreach ($options as $option) {
echo br(1);
echo $option['name'];
$checkboxattr = array(
'name' => $option['name'],
'value' => $option['name'],
'id' => $option['id']
); //'checkbox_'.
echo form_checkbox($checkboxattr);
echo "<span id='total_".strtolower($option['name'])."'></span>";
}
The blank array you mean is from this variable $checkboxattr?
In your view, did you get the value of array variable ($options) from the controller?
If so, have you passed it from the controller ? Because I don't see any codes in your controller that pass the array to your view.
The question: How do I generate navigation, allowing for applying different classes to different sub-items, from a multi-dimensional array?
Here is how I was doing it before I had any need for multi-level navigation:
Home
Pics
About
and was generated by calling nav():
function nav(){
$links = array(
"Home" => "home.php",
"Pics" => "pics.php",
"About" => "about.php"
);
$base = basename($_SERVER['PHP_SELF']);
foreach($nav as $k => $v){
echo buildLinks($k, $v, $base);
}
}
Here is buildLinks():
function buildLinks($name, $page, $selected){
if($selected == $page){
$theLink = "<li class=\"selected\">$name</li>\n";
} else {
$thelink = "<li>$name</li>\n";
}
return $thelink;
}
My question, again:
how would I achieve the following nav (and notice that the visible sub navigation elements are only present when on that specific page):
Home
something1
something2
Pics
About
and...
Home
Pics
people
places
About
What I've tried
From looking at it it would seem that some iterator in the SPL would be a good fit for this but I'm not sure how to approach this. I have played around with RecursiveIteratorIterator but I'm not sure how to apply a different style to only the sub menu items and also how to only show these items if you are on the correct page.
I built this array to test with but don't know how to work with the submenu1 items individually:
$nav = array(
array(
"Home" => "home.php",
"submenu1" => array(
"something1"=>"something1.php",
"something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php")
);
The following will print out the lot in order but how do I apply, say a class name to the submenu1 items or only show them when the person is on, say, the "Home" page?
$iterator = new RecursiveIteratorIterator(new RecursiveArrayIterator($nav));
foreach($iterator as $key=>$value) {
echo $key.' -- '.$value.'<br />';
}
And this gets me:
Home
something1
something2
Pics
About
But I have no way to apply classes to those sub items and no way to only display them conditionally because I don't see how to target just these elements.
Don't reinvent the wheel, use Zend_Navigation and you will be happy.
You were on the right track with RecursiveIteratorIterator. It essentially flattens a recursive iterator. Here is the correct way:
$nav = array(
array(
"Home" => "home.php",
"submenu1" => array(
"something1"=>"something1.php",
"something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php"),
);
$it = new RecursiveIteratorIterator(
new RecursiveArrayIterator($nav),
RecursiveIteratorIterator::SELF_FIRST
);
foreach ($it as $k => $v) {
if ($it->getDepth() == 0)
continue;
echo str_repeat(" ", $it->getDepth() - 1) .
"$k => $v\n";
}
gives
Home => home.php
submenu1 => Array
something1 => something1.php
something2 => something2.php
Pics => pics.php
About => about.php
It seems like you might want to do this in a more object oriented way.
If not, it seems like you should at least define an algorithm that makes sense, right now you are just blindly guessing. Instead, DEFINE.
For example:
I am defining my navigation to be a php hash based tree. A navigation item will have the following:
A) if there is a top level link, the array hash will contain an item(sub array) labeled "navigation leaf"
b) A navigation Leaf will contain elements labeled "Display value", "link value", and "alt value". These items will be used to generate an anchor tag.
c) if an element has a submenu, in addition to containing a "Navigation Leaf", a "subnavigation" element will be present. A subnavigation element will have a "Navigation Leaf" if it has a displayable navigation item.
You can then write functions/methods that will display your navigation based on the definition you choose.
What I would do, is something along these lines:
class MenuItem {
protected $active = false;
protected $children = array();
protected $name = '';
protected $link = '';
public function __construct($name, $link, $active) {}
public function __toString() {
//render this item
$out = ''; #render here
if (!$this->isActive()) {
return $out;
}
$out .= '<ul>';
foreach ($this->children as $child) {
$out .= (string) $child;
}
$out .= '</ul>';
return $out;
}
public function isActive() {
if ($this->active) {
return true;
}
foreach ($this->children as $child) {
if ($child->isActive()) {
return true;
}
}
return false;
}
}
Then, all you have is a collection of root menu items in an array... To build your menu, you just do:
$rootItems = array($item1, $item2);
$out = '<ul>';
foreach ($rootItems as $item) {
$out .= (string) $item;
}
$out .= '</ul>';
I'll leave the semantics of constructing the object, adding children, etc to the user...
What about rewrite nav function in the next way:
function nav($links, $level){
foreach($links as $k => $v) {
if (is_array($v)) {
nav($v, $level + 1)
} else {
echo buildLinks($k, $v, $base);
}
}
}
And than call it:
$links = array(
array(
"Home" => "home.php",
"submenu1" => array(
"something1"=>"something1.php",
"something2" => "something2.php")
),
array("Pics" => "pics.php"),
array("About" => "about.php")
);
nav($links, 0);
Simplest way, IMHO, is to just make a recursive call, and use a tree structured description of your navigation (that is, nested arrays). Untested example code:
<?php
$links = array(
"Home" => array("home.php", array(
"something1"=> array("something1.php", array()),
"hello"=> array("hello.php", array(
"world" => array("world.php", array()),
"bar" => array("bar.php", array()),
)),
)),
"Pics" => array("pics.php", array(
"people"=>"people.php",
"places" => "places.php",
)),
"About" => array("about.php", array()), // example no subitems
);
// use the following $path variable to indicate the current navigational position
$path = array(); // expand nothing
$path = array('Home'); // expand Home
$path = array('Home', 'hello'); // also expand hello in Home
// map indent levels to classes
$classes = array(
'item',
'subitem',
'subsubitem',
);
// recursive function to build navigation list
function buildNav($links, $path, $classes)
{
// selected page at current level
// NOTE: array_shift returns NULL if $path is empty.
// it also alters the array itself
$selected = array_shift($path);
$class = array_shift($classes);
echo "<ul>\n";
foreach($links as $name => $link)
{
list($href, $sublinks) = $link;
if ($name == $selected)
{
echo "<li class=\"selected $class\">$name\n";
// recursively show subitems
// NOTE: path starts now with the selected subitem
buildNav($sublinks, $path, $classes);
echo "</li>\n";
}
else
{
echo "<li>$name</li>\n";
}
}
echo "<ul>\n";
}
// actually build the navigation
buildNav($links, $path, $classes);
?>
#catchmeifyoutry
Thank you, you saved my life LoL.
I changed your function a little to adapt it to my use and this came out:
$html['navi'] = array(
"Home" => "/home/",
"DJs & Shows" => "/djs-shows/",
"Playlists" => "/playlists/",
"Newsbeat" => "/newsbeat/",
"Reviews" => "/reviews/",
"TV" => "/tv/",
"Contact" => "/contact/",
"Test" => array("/test/",
array("Submenu 1" => "/test/link1",
"Submenu 2" => "/test/link2",
"Submenu 3" => "/test/link3",
"Submenu 4" => "/test/link4",
"Submenu 5" => "/test/link5",
"Submenu 6" => "/test/link6"
)
)
);
$classes = array(
'first-level',
'second-level',
'third-level',
);
function siteNavi($links, $classes) {
// The best way for MultiArray navigation (LOVE IT!)
// Array Shift selects first element and removes it from array
$class = array_shift($classes);
echo "<ul class=\"$class\">\n";
foreach($links as $name => $link) {
if (is_array($link) AND $class != "") {
list($link, $sublinks) = $link;
if ($_GET['site'] == basename($link)) { $selected = ' class="current"'; } else { $selected = ""; }
echo "<li{$selected}>{$name}\n";
// recursively show subitems
// NOTE: path starts now with the selected subitem
siteNavi($sublinks, $classes);
echo "</li>\n";
} else {
if ($_GET['site'] == basename($link)) { $selected = ' class="current"'; } else { $selected = ""; }
echo "<li{$selected}><a href=\"{$link}\" >{$name}</a></li>\n";
}
}
echo "</ul>\n";
}
Thank you very much !
I wonder how much impact does have this kind of code on the page speed tho. Few microseconds of milliseconds :D