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
I'm trying to create a multidimensional array which stores a website navigation. Currently my navigation consists of Main -> Level 1 -> Level 2. I am having issues accessing level 2 correctly.
My Array example array is...
$pages = array
(
array('page_name' => 'Home'),
array('page_name' => 'About us', 'level_one' => array('first1','first2', 'level_two' => array('second'), 'first3')),
array('page_name' => 'Gallery', 'level_one' => array('first1','first2','first3','first4')),
array('page_name' => 'Contact us')
);
My code to retrieve the navigation so far is...
$count = count($pages);
for ($x=0; $x<$count; $x++) {
# echo yes for active page
if ($filename == $pages[$x][1]) { echo 'yes'; }
# echo main navigation
echo $pages[$x]['page_name'];
# check if the item has a sub page
$firstcount = count($pages[$x]['level_one']);
# if the item has a sub page echo
if ($firstcount > 0) { for ($y=0; $y<$firstcount; $y++) {
echo "\r\n" . '.' . $pages[$x]['level_one'][$y];
# check if the page has a sub page
$secondcount = count($pages[$x]['level_one']['level_two']);
if ($secondcount > 0) { for ($z=0; $z<$secondcount; $z++) {
if($pages[$x]['level_one']['level_two'][$z] != '') { echo "\r\n" . '..' . $pages[$x]['level_one']['level_two'][$z]; }
}}
} }
echo "\r\n";
}
And the output I'm currently getting is...
Home
About us
.first1
..second
.first2
..second
.first3
..second
.
..second
Gallery
.first1
.first2
.first3
.first4
Contact us
I am trying to create a multi level navigation. My expected output would be...
<!-- Expected output
Home
About us
.first1
.first2
..second
.first3
Gallery
.first1
.first2
.first3
.first4
Contact us
-->
I think you should check out some php recursion examples:
function returnArrayAsString($ar, $level = 0){
$str = '<ul class="level' . $level . '">';
foreach($ar as $k => $v){
if(is_array($v)){
$str .= '<li>' . $k . returnArrayAsString($v, $level + 1) . '</li>';
} else {
$str .= '<li>' . $v . '</li>';
}
}
$str .= '</ul>';
return $str;
}
if you then have a simple array:
$ar = array(
'Home',
'About us' => array(
'sub1a',
'sub1b',
'sub1c' => array(
'sub2a',
'sub2b'
)
)
);
Put array in function:
echo returnArrayAsString($ar);
This would give you a nice ordered list no matter the depth of sub items in the array.
As you can see, the function calls itself if it finds an array value. the $level variable can be used as a indicator, you could also use it for breadcrumbs ( About us > sub1c > sub2a).
Hope it helps....
The problem is in your loop code. Using foreach to make things more clear, results in the following, which outputs your result as you want it.
foreach($pages as $page)
{
echo "{$page['page_name']}\n";
foreach($page['level_one'] as $key => $level_one)
{
if($key === 'level_two')
{
foreach($level_one as $level_two)
{
echo "..$level_two\n";
}
}
else
{
echo ".$level_one\n";
}
}
}
You can use a lot of functions/ways to do this:
1.By foreach(Reference)
2.use var_dump to view any arrayvar_dump()
But remember to use <pre></pre> for prettifying.
Hello guys just want to ask a simple question. It is all about creating a navigation link.
Because I have a navigation link. And if the user choose a link the link will be highlighted and if the user click another link that link will be highlighted and the previous link will not. In creating my link I use an array and i loop it to call the action.
Here's my code
MY CONTROLLER
public function homepage(){
$data['title'] = "Welcome";
$data['copyright'] = date('Y');
$data['queryViewEntries'] = $this->category_model->viewAllEntry();
$data['link'] = "category";
$this->load->view('common/header_common',$data);
$this->load->view('common/navigation',$data);
$this->load->view('User/contents/homepage');
$this->load->view('common/footer_common',$data);
}
MY VIEW
<li class="nav-header"></li>
<?php
$highlight = $link;
$section = array(
'CATEGORIES' => 'user_controller/homepage',
'ITEMS' => 'item_controller/index',
'SUPPLIERS' => 'supplier_controller/index'
);
foreach($section as $key => $value){
echo "<li class='active'>".anchor($value,$key)."</li>"; //this is the problem how can i set the cliked link to active and the other will be not.
}
?>
</li>
I hope guys you can help me. Thanks.
https://www.codeigniter.com/user_guide/libraries/uri.html
//add to your controller
$data['url_link'] = $this->uri->segment(1, 0); //your URL segment /www.website/items
//view
foreach($section as $key => $value){
//class name
$className = ($key === $url_link) ? 'active' : 'no-active';
echo "<li class='$className'>".anchor($value,$key)."</li>";
}
first, you probably want to enclose your list in a < ul> and not close your list right after you open it. (your editor probably did you that favour).
In your loop, you need to check each key against the current link and apply a style accordingly. something like ....
<ul class="nav-header">
<?php
$highlight = $link;
$section = array(
'CATEGORIES' => 'user_controller/homepage',
'ITEMS' => 'item_controller/index',
'SUPPLIERS' => 'supplier_controller/index'
);
foreach($section as $key => $value){
if ($key == $link){
echo "<li class='active'>";
} else{
echo "<li class='inactive'>";
}
echo anchor($value,$key)."</li>";
}
?>
</ul>
You have to make sure that your 'section' array in your view and your $data['link'] have the same value. i.e. rename them to match e.g. in your controller
$data['link'] = 'CATEGORIES'
OR in your view
`$section = array(
'category' => 'user_controller/homepage',
.....
);
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.
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