Beste forum leden,

Ik krijg het maar niet voor elkaar om mijn menu items actief te maken. Alles werkt zoals ik het hebben wil zolang er geen items onder parents hangen.

Maar ik wil ook dat de parent active wordt als er een item die daaronder hangt aangeklikt wordt.

Dit is de code, ik hoop dat het een beetje duidelijk is:

<?php  function getMenu()
       {

       		// Select all entries from the menu table
			$result = mysql_query("SELECT * FROM menu_items WHERE status = 1 ORDER BY parent, sort, label");
            $num_rows = mysql_num_rows($result);          
            
			// Create a multidimensional array to contain a list of items and parents
			$menu = array
            (
			    'items' => array(),
			    'parents' => array()
			);
            
			// Builds the array lists with data from the menu table
			$menu_name = '';
            while ($items = mysql_fetch_assoc($result))
			{
			    // Creates entry into items array with current menu item id ie. $menu['items'][1]
			    $menu['items'][$items['id']] = $items;
			    // Creates entry into parents array. Parents array contains a list of all items with children
			    $menu['parents'][$items['parent']][] = $items['id'];
                
                $menu_name = 'menu_'.$items['id'];
  
			}
   
            $q = 'SELECT status FROM layouts WHERE position_id = "'.getPositionIdByPositionName('menu').'" AND page_id = "'.getPageIdByPage().'" '; 
            $result = mysql_query($q) or die(mysql_error());

            $menu_status_id = 0;
            while ($menu_status = mysql_fetch_assoc($result))
            {
            
            	$menu_status_id = $menu_status['status'];

            }   

                      if ( $menu_status_id == 1 )
                      {
                          echo  "<div id='menu'>";
                          echo buildMenu(0, $menu);
                          echo "</div>";
                      }	

       }
 
     		// Menu builder function, parentId 0 is the root
            function buildMenu($parent, $menu)
            {

               $html = "";
               if (isset($menu['parents'][$parent]))
               {
						
                  $html .= "
                  
                  <ul>\n";
                   foreach ($menu['parents'][$parent] as $itemId)
                   {
                      if(!isset($menu['parents'][$itemId]))
                      {
                         
                         if (getCurrentPage() == $menu['items'][$itemId]['link'])
                         {
                         	$active = "class='active'";
                         	
                         }
                         else
                         {
                         	$active = '';
                         	
                         }
                         
                         $html .= "<li ".$active.">\n  <a ".$active." href='".$menu['items'][$itemId]['link']."'>".$menu['items'][$itemId]['label']."</a>\n</li> \n";
                      }
                      if(isset($menu['parents'][$itemId]))
                      {
                         $html .= "
                         <li ".$active.">\n  <a ".$active." href='".$menu['items'][$itemId]['link']."'>".$menu['items'][$itemId]['label']."</a> \n";
                         $html .= buildMenu($itemId, $menu);
                         $html .= "</li> \n";
                      }
                   }
                   $html .= "</ul> \n";
               }
               return $html;
            } ?>
Wat is sort?

Ook een integer?
dus bv. parent = "fruit", id=5

Dan hebben alle children van fruit parent=5. "appel" heeft sort=1; peer heeft sort=2, ...
Dan komt appel boven peer. Juist?

---

Wat is precies je systeem om te bepalen wat de hoofd-items zijn?
Hoe weet je dat fruit een hoofd-item is?
Kris Peeters op 13/09/2013 13:16:05

Wat is sort?

Ook een integer?
dus bv. parent = "fruit", id=5

Dan hebben alle children van fruit parent=5. "appel" heeft sort=1; peer heeft sort=2, ...
Dan komt appel boven peer. Juist?

---

Wat is precies je systeem om te bepalen wat de hoofd-items zijn?
Hoe weet je dat fruit een hoofd-item is?


Sort is bedoeld om aan te geven in welke volgorde deze komt te staan in het menu. Dit is inderdaad een integer.

Jouw voorbeeld klopt precies inderdaad!

Als je een item geen parent toewijst, dus parent = 0 dan wordt het gezien als hoofd item.









Okay.

Hoe diep gaat de hierarchie?
HoofdItems, subItems, subSubItems, ...?

Kris Peeters op 13/09/2013 13:40:04

Okay.

Hoe diep gaat de hierarchie?
HoofdItems, subItems, subSubItems, ...?



Klopt, ik kan onder een hoofditem een subitem hangen en daar onder weer een subsubitem. Kan nog wel verder ook, ik heb een voorbeeldje toegevoegd om het geheel wat duidelijk te maken.





Klassiek voorbeeld van de problemen die je tegen komt als je een hierarchische structuur in een normale database wilt proppen.... 'da werk nie'.
Als je een echte oplossing voor je probleem wilt hebben (en de toekomstige problemen die je vast nog gaat tegen komen) dan zal je moeten kijken naar een nested set model: http://en.wikipedia.org/wiki/Nested_set_model
Niet makkelijk, wel de oplossing. Met zo'n nested set zou dit probleem namelijk in 5 seconden zijn opgelost.

Zolang je dat niet hebt zal je extra loops moeten maken. Je bouwt je boom op als je de data uit de database hebt gehaald en checkt dan het record dat 'active' moet zijn. Als je alle keys hebt van dat item, dan loop je door die keys heen en geef je een extra element aan elke node die daarbij hoort.
Erwin H op 13/09/2013 14:19:35

Klassiek voorbeeld van de problemen die je tegen komt als je een hierarchische structuur in een normale database wilt proppen.... 'da werk nie'.
Als je een echte oplossing voor je probleem wilt hebben (en de toekomstige problemen die je vast nog gaat tegen komen) dan zal je moeten kijken naar een nested set model: http://en.wikipedia.org/wiki/Nested_set_model
Niet makkelijk, wel de oplossing. Met zo'n nested set zou dit probleem namelijk in 5 seconden zijn opgelost.

Zolang je dat niet hebt zal je extra loops moeten maken. Je bouwt je boom op als je de data uit de database hebt gehaald en checkt dan het record dat 'active' moet zijn. Als je alle keys hebt van dat item, dan loop je door die keys heen en geef je een extra element aan elke node die daarbij hoort.


Klopt Erwin,

Ik had al de grootste moeitte om het zo werkend te krijgen. Ik ben er inmiddels wel bijna, ik kan zowel de parent als de subitem active zetten. ALLEEN snap ik nog niet hoe ik ervoor kan zorgen dat mijn parent active wordt als ik een subitem aanlik.


Bekijk dit eens.

Dus, ik voeg een extra ['active']=1 toe aan de hiƫrarchie; aan de parent; diens parent, diens parent ...
Dat wordt toegevoegd aan de array.

Dus, jij kan, bij het printen van de array iets doen als

echo '<a href="..."'
if(!empty($item['active'])) {
echo ' class="active"';
}
echo '>...</a>';

Ik denk dat ik zo ongeveer de zelfde DB tabel heb als de jouwe (qua structuur)

<?php
/*
CREATE TABLE  `phphulp`.`menu_items` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY ,
`parent` INT NOT NULL DEFAULT  '0',
`sort` INT NOT NULL DEFAULT  '0',
`label` VARCHAR( 255 ) NOT NULL ,
`link` VARCHAR( 255 ) NOT NULL ,
`status` INT NOT NULL DEFAULT  '0',
`created` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE = INNODB;

INSERT INTO `menu_items` (`id`, `parent`, `sort`, `label`, `link`, `status`, `created`) VALUES
(1, 0, 0, 'Fruit', '?p=fruit', 1, '2013-09-13 13:26:07'),
(2, 0, 0, 'Groenten', '?p=groenten', 1, '2013-09-13 13:26:51'),
(3, 1, 1, 'Appel', '?p=appel', 1, '2013-09-13 13:28:11'),
(4, 1, 2, 'Peer', '?p=peer', 1, '2013-09-13 13:28:27'),
(5, 1, 3, 'Banaan', '?p=banaan', 1, '2013-09-13 13:28:42'),
(6, 2, 1, 'Wortel', '?p=wortel', 1, '2013-09-13 13:29:13'),
(7, 2, 2, 'Aardappel', '?p=aardappel', 1, '2013-09-13 13:29:29'),
(8, 3, 1, 'Jonagold', '?p=jonagold', 1, '2013-09-13 14:32:44'),
(9, 3, 1, 'Golden', '?p=golden', 1, '2013-09-13 14:33:02');
*/


// okay, stel, we zoeken de jonagold.  id=8
// dan verwachten we dat "jonagold > appel > fruit" actief worden.
$get_id = 8;

$mysqli = new mysqli('localhost', 'root', '', 'phphulp');  // zelf aanpassen
$sql = "SELECT id, parent, sort, label, link, status, created 
  FROM menu_items 
  ORDER BY parent, sort";

///////////////////////////////
// Items halen en in array steken
$items = array();
$res = $mysqli->query($sql);
while($row = $res->fetch_assoc()) {
  $items[] = $row;
}

///////////////////////////////
// actief maken.  Je krijgt gratis een breadcrumb. ...
$breadcrumb = searchInItems($items, $get_id);
echo '<hr>Breadcrumb: <pre>' . print_r($breadcrumb, 1) . '</pre>';
echo '<hr>Items: <pre>' . print_r($items, 1) . '</pre>';

/**
* recursieve functie.  zoekt het item met gegeven id.  Geeft je een breadcrumb (omgekeerde volgorde).
* Alle items in de breadcrumb krijgen een ['active']=1
* $items wordt by ref doorgegeven, zo kunnen we de gegevens aanpassen.
*/
function searchInItems(&$items, $id, $breadcrumb = array()) {
  foreach ($items as $key=>$item) {
    if($item['id'] == $id) {
      $items[$key]['active'] = 1;
      $breadcrumb[] = $item;
      $a = searchInItems($items, $item['parent'], $breadcrumb);
      if ($a) {
        return $a;
      }
      break;
    }
  }
  return $breadcrumb;
}
?>


-----------------------
En misschien heb je hier ook nog iets aan.
Zelfde gegevens. Zelfde variabele $items

<?php
...
$itemsInHierarchy = putInHierarchy($items);
echo '<hr><pre>' . print_r($itemsInHierarchy, 1) . '</pre>';
/**
* recursieve functie.  Zet alles in een hierarchische, multidimentionele array
*/
function putInHierarchy($items, $parent=0) {
  $siblings = array();  // broers en zussen
  foreach ($items as $key=>$item) {
    // zijn het broers of zussen?
    if ($item['parent'] == $parent) {
      // hoofditem
      $siblings[$item['id']] = array(
        'item' => $item,
        'children' => putInHierarchy($items, $item['id'])
      );
    }
  }
  return $siblings;
}
?>
Ziet er erg goed uit Kris! Gaat vast en zeker werken, alleen ik weet niet goed hoe ik dit moet implementeren in mijn huidige opstelling. Als u teamviewer heeft zou dit fantastisch zijn anders ga ik nog wel even goed kijken.

Nogmaals super bedankt voor de code en hulp!

@Furio

Een heel bericht quoten als het er direct boven staat is nogal onnodig.... en enigszins vervelend lezen.
Erwin H op 13/09/2013 15:22:52

@Furio

Een heel bericht quoten als het er direct boven staat is nogal onnodig.... en enigszins vervelend lezen.


Excuses, heb het gewijzigd.

Reageren