geen submenu
Ik ben een code aan het omzetten van een HTML code naar een PHP die alles uit een database haalt.
De code bevat een stukje de het menu moet tonen. Met behulp van <li> en <lu>
Nu lukt het mij niet om de submenu's er in te krijgen.
Hieronder staan eerst de HTML code zoals die is, dan hoe die door de PHP code wordt gemaakt en als derde de php code die de html code moet maken.
Wie weet er wat ik fout doe?
html-code moet ongeveer dit zijn
Code (php)
1
2
3
4
5
6
7
8
9
10
11
2
3
4
5
6
7
8
9
10
11
<li><a href="inkomsten-uitgaven.html" class="active">inkomsten & uitgaven</a></li>
<li><a href="beheer.html">beheer</a>
<ul>
<li><a href="b-t-w.html">b.t.w.</a></li>
</ul>
</li>
<li><a href="administraties.php">administraties</a>
<ul>
<li><a href="administratie.php">nieuwe administratie</a></li>
</ul>
</li>
<li><a href="beheer.html">beheer</a>
<ul>
<li><a href="b-t-w.html">b.t.w.</a></li>
</ul>
</li>
<li><a href="administraties.php">administraties</a>
<ul>
<li><a href="administratie.php">nieuwe administratie</a></li>
</ul>
</li>
Deze html-code wordt genereerd!
Code (php)
1
2
3
2
3
<li><a href="inkomsten-uitgaven.html" class="active">inkomsten & uitgaven</a></li>
<li><a href="beheer.html">beheer</a></li>
<li><a href="administraties.php">administraties</a></li>
<li><a href="beheer.html">beheer</a></li>
<li><a href="administraties.php">administraties</a></li>
Hier onder volgt mijn php code
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
<?php // *** menu ****
// menu ombouwen naar database menu
$menu_query1 = "SELECT * FROM tabel_menu WHERE menu_sub_van = 0 ORDER BY menu_waarde ASC";
$menu_result1 = mysqli_query($connect, $menu_query1);
$menu_count1 = mysqli_num_rows($menu_result1);
$num_row = 0;
while ($menu_row1 = mysqli_fetch_array($menu_result1, MYSQLI_ASSOC)) {
$num_row ++;
$menu_plaatsen[$num_row] = "<li><a href='" . $menu_row1['menu_link'] . "' class='active'>" . $menu_row1['menu_tekst'] . "</a>";
$menu_query2 = "SELECT * FROM tabel_menu WHERE menu_waarde = " . $menu_row1['menu_sub_van'] . " ORDER BY menu_waarde ASC";
$menu_result2 = mysqli_query($connect, $menu_query2);
$menu_count2 = mysqli_num_rows($menu_result2);
if ($menu_count2 == 0) {
$num_row ++;
$menu_plaatsen[$num_row] = "</li>";
} else { //$menu_count2 >> 0 dus er zijn geen submenu's
$num_row ++;
$menu_plaatsen[$num_row] = "<ul>";
while ($menu_row2 = mysqli_fetch_array($menu_result2, MYSQLI_ASSOC)) {
$num_row ++;
$menu_plaatsen[$num_row] = "<li><a href='" . $menu_row2['menu_link'] . ">" . $menu_row2['menu_tekst'] . "</a></li>";
$num_row ++;
}
$menu_plaatsen[$num_row] = "</ul>";
mysqli_free_result($menu_result2);
$num_row ++;
$menu_plaatsen[$num_row] = "</li>";
}
}
mysqli_free_result($menu_result1);
?>
<nav class="art-nav">
<ul class="art-hmenu">
<?php
foreach ($menu_plaatsen as $plaatsen){
echo($plaatsen);
}
?>
</ul>
</nav>
<?php // *** einde menu ****
?>
// menu ombouwen naar database menu
$menu_query1 = "SELECT * FROM tabel_menu WHERE menu_sub_van = 0 ORDER BY menu_waarde ASC";
$menu_result1 = mysqli_query($connect, $menu_query1);
$menu_count1 = mysqli_num_rows($menu_result1);
$num_row = 0;
while ($menu_row1 = mysqli_fetch_array($menu_result1, MYSQLI_ASSOC)) {
$num_row ++;
$menu_plaatsen[$num_row] = "<li><a href='" . $menu_row1['menu_link'] . "' class='active'>" . $menu_row1['menu_tekst'] . "</a>";
$menu_query2 = "SELECT * FROM tabel_menu WHERE menu_waarde = " . $menu_row1['menu_sub_van'] . " ORDER BY menu_waarde ASC";
$menu_result2 = mysqli_query($connect, $menu_query2);
$menu_count2 = mysqli_num_rows($menu_result2);
if ($menu_count2 == 0) {
$num_row ++;
$menu_plaatsen[$num_row] = "</li>";
} else { //$menu_count2 >> 0 dus er zijn geen submenu's
$num_row ++;
$menu_plaatsen[$num_row] = "<ul>";
while ($menu_row2 = mysqli_fetch_array($menu_result2, MYSQLI_ASSOC)) {
$num_row ++;
$menu_plaatsen[$num_row] = "<li><a href='" . $menu_row2['menu_link'] . ">" . $menu_row2['menu_tekst'] . "</a></li>";
$num_row ++;
}
$menu_plaatsen[$num_row] = "</ul>";
mysqli_free_result($menu_result2);
$num_row ++;
$menu_plaatsen[$num_row] = "</li>";
}
}
mysqli_free_result($menu_result1);
?>
<nav class="art-nav">
<ul class="art-hmenu">
<?php
foreach ($menu_plaatsen as $plaatsen){
echo($plaatsen);
}
?>
</ul>
</nav>
<?php // *** einde menu ****
?>
Ik weet zeker dat je hier beter naar recursie kan kijken, en een minimalisatie van het aantal queries.
Laten we dit voorbeeld van structuur eens aanhouden, om je menu's mee op te stellen, waarbij feitelijk oneindig veel levels kan maken.
Dan loont het om de boel met een enkele query op te halen, de array samen te stellen, en met een aparte functie de recursie toe te passen:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?php
// get all menuitems with 1 query
$result = $conn->query("
SELECT
id, parentId, name
FROM
menu
ORDER BY
parentId, name
");
// prepare special array with parent-child relations
$menuData = array(
'items' => array(),
'parents' => array()
);
while ($menuItem = $result->fetch_assoc())
{
$menuData['items'][$menuItem['id']] = $menuItem;
$menuData['parents'][$menuItem['parentId']][] = $menuItem['id'];
}
// menu builder function, parentId 0 is the root
function buildMenu($parentId, $menuData)
{
$html = '';
if (isset($menuData['parents'][$parentId]))
{
$html = '<ul>';
foreach ($menuData['parents'][$parentId] as $itemId)
{
$html .= '<li>' . $menuData['items'][$itemId]['name'];
// find childitems recursively
$html .= buildMenu($itemId, $menuData);
$html .= '</li>';
}
$html .= '</ul>';
}
return $html;
}
// output the menu
echo buildMenu(0, $menuData);
?>
// get all menuitems with 1 query
$result = $conn->query("
SELECT
id, parentId, name
FROM
menu
ORDER BY
parentId, name
");
// prepare special array with parent-child relations
$menuData = array(
'items' => array(),
'parents' => array()
);
while ($menuItem = $result->fetch_assoc())
{
$menuData['items'][$menuItem['id']] = $menuItem;
$menuData['parents'][$menuItem['parentId']][] = $menuItem['id'];
}
// menu builder function, parentId 0 is the root
function buildMenu($parentId, $menuData)
{
$html = '';
if (isset($menuData['parents'][$parentId]))
{
$html = '<ul>';
foreach ($menuData['parents'][$parentId] as $itemId)
{
$html .= '<li>' . $menuData['items'][$itemId]['name'];
// find childitems recursively
$html .= buildMenu($itemId, $menuData);
$html .= '</li>';
}
$html .= '</ul>';
}
return $html;
}
// output the menu
echo buildMenu(0, $menuData);
?>
Bron: Crisp's Tweakblog
Gewijzigd op 24/01/2020 15:15:34 door - Ariën -
+1 voor Ariën er van uitgaande dat de code werkt :-)
Thnx to Crisp ;-)
Mogelijke andere optimalisaties: output escaping, en output buffering i.p.v. HTML breien.
Bij mij werkte het niet direct, en ik moest dus vogelen om het wel werkend te krijgen. Ik kwam daar niet uit.
Ik begin niet met <ul> omdat die afwijkt van alle <ul>s die ik verder nog heb.
Dus ik moet beginnen met <li> en dan later als er een sub is moet ik de </li> uitstellen tot na de zoveelste </ul>
Ik heb aan het begin wel bedacht dat ik de volgorde in sql kan bepalen.
Code (php)
1
$menu_result = $connect->query("SELECT * FROM tabel_menu ORDER BY menu_sub_van, menu_waarde");
Van daar uit zal ik het denk ik naar een array moeten zetten, om de verschillende niveaus van de menu's te onderscheiden van elkaar. Ik ben niet zo thuis in het gebruik van foreach(...){...}
Hoeveel kan ik in een variabele stoppen?
Want ik dacht een array te moeten gebruiken om iedere regel in een eigen (array-)variabele te zetten. Maar als ik de code van -Ariën- bekijk, dan denk ik dat ik zie dat de variabele html gevuld wordt, en dat die vervolgens in het html deel getoond kan worden.
Quote:
Ik begin niet met <ul> omdat die afwijkt van alle <ul>s die ik verder nog heb.
Dus ik moet beginnen met <li> en dan later als er een sub is moet ik de </li> uitstellen tot na de zoveelste </ul>
Dus ik moet beginnen met <li> en dan later als er een sub is moet ik de </li> uitstellen tot na de zoveelste </ul>
Je bedoelt dat de styling afwijkt? Dan moet je de styling aanpassen. een <li> hoort gewoon in een <ul>.
Een foreach is niks meer dan een loop, waarmee je door een array kan wandelen.
Hoe je zo'n array genereert uit database resultaten kan met mysqli_fetch_array of als je hier zelf controle over wilt moet je deze zelf opbouwen, zoals in het voorbeeld van Arien regel 18 tm 22.
Gewijzigd op 29/01/2020 19:41:20 door Michael -
Met deze code lukt het me nu wel.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
// menu builder function, parentId 0 is the root
function buildMenu($parentId, $menuData)
{
$html = '';
if (isset($menuData['parents'][$parentId]))
{
if ($parentId==0)
{
$html = '<ul class="art-hmenu">';
}
else
{
$html = '<ul>';
}
foreach ($menuData['parents'][$parentId] as $itemId)
{
$html .= '<li><a href="">' . $menuData['items'][$itemId]['menu_tekst'] . '</a>';
// find childitems recursively
$html .= buildMenu($itemId, $menuData);
$html .= '</li>';
}
$html .= '</ul>';
}
return $html;
}
function buildMenu($parentId, $menuData)
{
$html = '';
if (isset($menuData['parents'][$parentId]))
{
if ($parentId==0)
{
$html = '<ul class="art-hmenu">';
}
else
{
$html = '<ul>';
}
foreach ($menuData['parents'][$parentId] as $itemId)
{
$html .= '<li><a href="">' . $menuData['items'][$itemId]['menu_tekst'] . '</a>';
// find childitems recursively
$html .= buildMenu($itemId, $menuData);
$html .= '</li>';
}
$html .= '</ul>';
}
return $html;
}
Met een lege href komt de bezoeker niet echt ver ;-)
Nogmaals Heel erg bedankt. Vooral voor het inzicht wat je me gaf.
Gewijzigd op 29/01/2020 23:48:33 door Frits van Leeuwen
Ik had 3 items in het hoofmenu. Alleen de tweede had een submenu. Ik zet verander ook de derde naar een menu-item met submenu, en nu verschijnt alleen het hoofdmenu-item.
Als ik er een vierde hoofdmenu-item aan toevoeg, werkt dat wel.
Ik zie nu niet wat ik fout heb gedaan.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
<?php // *** menu ****
$result = $connect->query("SELECT * FROM tabel_menu ORDER BY menu_sub_van, menu_waarde");
// prepare special array with parent-child relations
$menuData = array(
'items' => array(),
'parents' => array()
);
while ($menuItem = $result->fetch_assoc())
{
$menuData['items'][$menuItem['menu_id']] = $menuItem;
$menuData['parents'][$menuItem['menu_sub_van']][] = $menuItem['menu_id'];
}
// menu builder function, parentId 0 is the root
function buildMenu($parentId, $menuData)
{
$html = '';
if (isset($menuData['parents'][$parentId]))
{
if ($parentId==0)
{
$html = '<ul class="art-hmenu">';
}
else
{
$html = '<ul>';
}
foreach ($menuData['parents'][$parentId] as $itemId)
{
$html .= '<li><a href="">' . $menuData['items'][$itemId]['menu_tekst'] . '</a>';
// find childitems recursively
$html .= buildMenu($itemId, $menuData);
$html .= '</li>';
}
$html .= '</ul>';
}
return $html;
}
// output the menu
?>
<nav class="art-nav">
<?php
echo buildMenu(0, $menuData);
?>
</ul>
</nav>
<?php // *** einde menu ****
?>
$result = $connect->query("SELECT * FROM tabel_menu ORDER BY menu_sub_van, menu_waarde");
// prepare special array with parent-child relations
$menuData = array(
'items' => array(),
'parents' => array()
);
while ($menuItem = $result->fetch_assoc())
{
$menuData['items'][$menuItem['menu_id']] = $menuItem;
$menuData['parents'][$menuItem['menu_sub_van']][] = $menuItem['menu_id'];
}
// menu builder function, parentId 0 is the root
function buildMenu($parentId, $menuData)
{
$html = '';
if (isset($menuData['parents'][$parentId]))
{
if ($parentId==0)
{
$html = '<ul class="art-hmenu">';
}
else
{
$html = '<ul>';
}
foreach ($menuData['parents'][$parentId] as $itemId)
{
$html .= '<li><a href="">' . $menuData['items'][$itemId]['menu_tekst'] . '</a>';
// find childitems recursively
$html .= buildMenu($itemId, $menuData);
$html .= '</li>';
}
$html .= '</ul>';
}
return $html;
}
// output the menu
?>
<nav class="art-nav">
<?php
echo buildMenu(0, $menuData);
?>
</ul>
</nav>
<?php // *** einde menu ****
?>
Parent en ParentID lijkt mij toch juist logische benamingen? In mijn ogen is dit juist vragen om om problemen.
Gewijzigd op 01/02/2020 20:03:59 door - Ariën -
- je zou dit altijd als argument mee kunnen geven aan de functie ($class=''), en als deze parameter niet-leeg is zou je een bijbehorende property weg kunnen schrijven naar de (buitenste) UL-tag
- je zou de buitenste UL-tag buiten de functie kunnen trekken, je hoeft eigenlijk alleen maar een UL-tag te openen als je de recursie induikt (een element children / subelementen heeft)
- je zou een omvattende div kunnen maken die een class heeft en op die manier alles stylen; en dit doe je in het bovenstaande fragment al, dus waarom heb je dan die art-hmenu nodig?
We kunnen ook niet echt zien wat er misgaat, omdat we de inhoud van $menuData niet kennen.
En mogelijk:
- zit er iets in de verbanden van de records mis zodat het geen goede boomstructuur betreft
- gaat er iets mis met de HTML-output (hoe ziet de uiteindelijke HTML code er uit?)
- zit er iets mis in de CSS-opmaak zodat niet alles goed weergegeven wordt?
Voor het oplossen van deze puzzel hebben we meer informatie nodig, zodat we kunnen nabootsen wat er misgaat.
Een iets andere aanpak lost al het bovenstaande op: start enkel een UL als je subitems hebt, en duik dan de recursie in. Dus bijvoorbeeld als volgt:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php
// items uit database - parent 0 = root van de te bouwen boom
$myItems = array(
1 => array('parent' => 0, 'data' => '1 een'),
2 => array('parent' => 1, 'data' => '1.1 een punt een'),
3 => array('parent' => 2, 'data' => '1.1.1 een punt een punt een'),
4 => array('parent' => 1, 'data' => '1.2 een punt twee'),
5 => array('parent' => 0, 'data' => '2 twee'),
6 => array('parent' => 5, 'data' => '2.1 twee punt een'),
7 => array('parent' => 0, 'data' => '3 drie'),
);
// initiele boom
$myTree = array(
0 => array(
'data' => 'root',
'children' => array(),
),
);
// bouw boom mbv items
foreach ($myItems as $id => $data) {
$myTree[$id] = array(
'data' => $data['data'],
'children' => array(),
);
$myTree[$data['parent']]['children'][] = $id;
}
// weergavefunctie
function displayTree($tree, $index=0) {
foreach ($tree[$index]['children'] as $child) {
?><li><?php echo $tree[$child]['data']; ?><?php
if (count($tree[$child]['children']) > 0) {
?><ul><?php
displayTree($tree, $child);
?></ul><?php
}
?></li><?php
}
}
// weergave
if (count($myItems) > 0) {
?><ul class="whatever"><?php
displayTree($myTree);
?></ul><?php
}
?>
// items uit database - parent 0 = root van de te bouwen boom
$myItems = array(
1 => array('parent' => 0, 'data' => '1 een'),
2 => array('parent' => 1, 'data' => '1.1 een punt een'),
3 => array('parent' => 2, 'data' => '1.1.1 een punt een punt een'),
4 => array('parent' => 1, 'data' => '1.2 een punt twee'),
5 => array('parent' => 0, 'data' => '2 twee'),
6 => array('parent' => 5, 'data' => '2.1 twee punt een'),
7 => array('parent' => 0, 'data' => '3 drie'),
);
// initiele boom
$myTree = array(
0 => array(
'data' => 'root',
'children' => array(),
),
);
// bouw boom mbv items
foreach ($myItems as $id => $data) {
$myTree[$id] = array(
'data' => $data['data'],
'children' => array(),
);
$myTree[$data['parent']]['children'][] = $id;
}
// weergavefunctie
function displayTree($tree, $index=0) {
foreach ($tree[$index]['children'] as $child) {
?><li><?php echo $tree[$child]['data']; ?><?php
if (count($tree[$child]['children']) > 0) {
?><ul><?php
displayTree($tree, $child);
?></ul><?php
}
?></li><?php
}
}
// weergave
if (count($myItems) > 0) {
?><ul class="whatever"><?php
displayTree($myTree);
?></ul><?php
}
?>
Dit levert:
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
<ul class="whatever">
<li>1 een<ul>
<li>1.1 een punt een<ul>
<li>1.1.1 een punt een punt een</li>
</ul></li>
<li>1.2 een punt twee</li>
</ul></li>
<li>2 twee<ul>
<li>2.1 twee punt een</li>
</ul></li>
<li>3 drie</li>
</ul>
<li>1 een<ul>
<li>1.1 een punt een<ul>
<li>1.1.1 een punt een punt een</li>
</ul></li>
<li>1.2 een punt twee</li>
</ul></li>
<li>2 twee<ul>
<li>2.1 twee punt een</li>
</ul></li>
<li>3 drie</li>
</ul>
Gewijzigd op 01/02/2020 23:21:00 door Thomas van den Heuvel
Maar vooral bedankt voor de uitleg. En voor het nieuwe alternatief dat je mij gaf.
Ik vroeg me alleen af, of dat ik door het begin niet gelijk gelimiteerd ben.
(zie de code onderaan)
Want ik wil juist zo open mogelijk blijven.
Ik heb bewust het menu in een database gezet om niet steeds in de code het menu aan te moeten passen. Dit biedt mij in de toekomst meer vrijheid.
-Arieën-
Half Engels half Nederlands komt door dat ik in het Nederlands ben begonnen met het opzetten van de database. Ik heb al wel meer code die met de database te maken heeft, en ik had geen zien om ook die code aan te passen. Gewoon om het werkende deel werkend te houden en me te kunnen focussen op dit onderdeel.
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
<?php
// items uit database - parent 0 = root van de te bouwen boom
$myItems = array(
1 => array('parent' => 0, 'data' => '1 een'),
2 => array('parent' => 1, 'data' => '1.1 een punt een'),
3 => array('parent' => 2, 'data' => '1.1.1 een punt een punt een'),
4 => array('parent' => 1, 'data' => '1.2 een punt twee'),
5 => array('parent' => 0, 'data' => '2 twee'),
6 => array('parent' => 5, 'data' => '2.1 twee punt een'),
7 => array('parent' => 0, 'data' => '3 drie'),
);
[/code]
// items uit database - parent 0 = root van de te bouwen boom
$myItems = array(
1 => array('parent' => 0, 'data' => '1 een'),
2 => array('parent' => 1, 'data' => '1.1 een punt een'),
3 => array('parent' => 2, 'data' => '1.1.1 een punt een punt een'),
4 => array('parent' => 1, 'data' => '1.2 een punt twee'),
5 => array('parent' => 0, 'data' => '2 twee'),
6 => array('parent' => 5, 'data' => '2.1 twee punt een'),
7 => array('parent' => 0, 'data' => '3 drie'),
);
[/code]
Gewijzigd op 02/02/2020 00:15:43 door Frits van Leeuwen
Als je tijdens het bouwen van deze set het stramien:
Code (php)
1
2
3
4
5
2
3
4
5
$myItems[<record id>] = array(
'parent' => <parent id>,
'data' => '<label tekst>',
// en wat je hier nog meer wilt toevoegen, of breng dit in 'data' onder
);
'parent' => <parent id>,
'data' => '<label tekst>',
// en wat je hier nog meer wilt toevoegen, of breng dit in 'data' onder
);
hanteert dan werkt de rest "vanzelf".
Gewijzigd op 02/02/2020 00:29:40 door Thomas van den Heuvel
Frits van Leeuwen op 02/02/2020 00:12:49:
Half Engels half Nederlands komt door dat ik in het Nederlands ben begonnen met het opzetten van de database. Ik heb al wel meer code die met de database te maken heeft, en ik had geen zien om ook die code aan te passen. Gewoon om het werkende deel werkend te houden en me te kunnen focussen op dit onderdeel.
Het kan geen kwaad om in hetzelfde stramien te werken qua naamgevingen. Dan kunnen andere mensen ook direct aan je code sleutelen of mee-debuggen zonder de hele applicatie door te worstelen. Het ergste voorbeeld wat ik ooit tegen kwam was iemand die zijn code in het Esperanto had benoemd. Als je dat niet kent, en dingen lijken op elkaar, dan ga je ze echt door elkaar halen.
Code (php)
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
// items uit database - parent 0 = root van de te bouwen boom
$myItems = array(
1 => array('parent' => 0, 'data' => '1 een'),
2 => array('parent' => 1, 'data' => '1.1 een punt een'),
3 => array('parent' => 2, 'data' => '1.1.1 een punt een punt een'),
4 => array('parent' => 1, 'data' => '1.2 een punt twee'),
5 => array('parent' => 0, 'data' => '2 twee'),
6 => array('parent' => 5, 'data' => '2.1 twee punt een'),
7 => array('parent' => 0, 'data' => '3 drie'),
);
$myItems = array(
1 => array('parent' => 0, 'data' => '1 een'),
2 => array('parent' => 1, 'data' => '1.1 een punt een'),
3 => array('parent' => 2, 'data' => '1.1.1 een punt een punt een'),
4 => array('parent' => 1, 'data' => '1.2 een punt twee'),
5 => array('parent' => 0, 'data' => '2 twee'),
6 => array('parent' => 5, 'data' => '2.1 twee punt een'),
7 => array('parent' => 0, 'data' => '3 drie'),
);
Code (php)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
$query="SELECT menu_id, menu_tekst, menu_waarde, menu_sub_van, menu_link, menu_reg_date FROM tabel_menu ORDER BY menu_sub_van, menu_waarde";
$result = mysqli_query($connect, $query);
$myItems = array(
'parent' => array(),
'data' => array()
);
foreach ( mysqli_fetch_assoc($result) as $row )
{
$myItems = array (
$row['menu_id'] => array(
'parent' => $row['menu_sub_van'],
'data' => $row['menu_tekst'],
),
);
}
$result = mysqli_query($connect, $query);
$myItems = array(
'parent' => array(),
'data' => array()
);
foreach ( mysqli_fetch_assoc($result) as $row )
{
$myItems = array (
$row['menu_id'] => array(
'parent' => $row['menu_sub_van'],
'data' => $row['menu_tekst'],
),
);
}
Die hardcoded array moet je overigens wel vertalen naar een set data uit je database. Nu overschrijf je met de array voor je structuur je bestaande data.
De array die Thomas van den Hoeven in zijn code had geplaatst moet natuurlijk worden omgebouwd naar mijn database en informatie. Daarom heb ik bij de query geen * gebruikt, maar alle velden genoemd die ik heb.
De query is goed, en die wil ik gebruiken voor het opbouwen van een menu. Maar deze code gaat gewoon fout.
Ik krijg een aantal regels die dit zeggen:
Warning: Illegal string offset 'menu_sub_van' in /.../menu.php on line 13
Warning: Illegal string offset 'menu_tekst' in /.../menu.php on line 14
Dus vergeet die array $myItems uiteindelijk, en haal alles uit de database op.
Trouwens, je zit nu wel zijn voorbeeld nog eens volledig de vernieling in te helpen. Want hij heeft de als voorbeeld gemaakte $myItem, en de vaste $myTree, en die laatste noem jij ook vrolijk $myItems. Dan kan je verwachten dat de code opeens heel vreemd gaat doen.
Gewijzigd op 06/02/2020 14:57:38 door - Ariën -
myItems zijn in wezen de records uit je database die je tijdelijk in een array onderbrengt.
myTree is vervolgens de structuur die je bouwt door het doorlopen van myItems.
Je zou de twee natuurlijk ook kunnen combineren door on-the-fly de boom te bouwen en enkel hierin de informatie weg te schrijven die je uit de database opvraagt. Daarin ben je helemaal vrij. Maar het kan in sommige gevallen handig zijn om data en structuur gescheiden te houden. Stel dat je de data wilt (her)gebruiken om meer bomen te kunnen bouwen oid.
Anyway, ik ben nog nooit de vorm "foreach ( mysqli_fetch_assoc($result) as $row )" tegengekomen en weet ook niet zeker of dat gaat werken.
Een overweging om mee te nemen in je ontwerp is de volgende: normaal gesproken zullen items op volgorde aangemaakt worden. Dus het kan dan nooit voorkomen dat een child id een lager nummer heeft dan de parent. Maar dit zou dus over tijd kunnen veranderen op het moment dat je met elementen in de boom gaat schuiven. Bij het bouwen van de boom is het in ieder geval belangrijk dat je een zodanige volgorde hanteert dat je altijd de parents ophaalt voor de children, anders wordt het bouwen van de boom nogal problematisch :p. Daartoe wordt meestal extra "meta data" opgeslagen over de boom. Hiertoe wordt meestal een redundant veld "depth" of "level" of wat dan ook opgeslagen. Als je in je query je resultaten sorteert op dit veld dan garandeert dit dat de items voldoende op volgorde staan om de boom te kunnen bouwen. Daarnaast komt het ook voor dat je kunt schuiven met elementen op een zeker niveau in de boom, dus ook een volgorde veld, "order" ofzo, kan (zeer) handig zijn.
Anyhow, als dit allemaal (nog) niet op jouw situatie van toepassing is (maar het is nog steeds verstandig om te overwegen om zoiets in te bouwen), dan zou je gewoon met een while-loop je boom kunnen bouwen zoals je nu doet, zonder al deze sorteer-criteria (maar expliciet een ORDER BY toevoegen kan natuurlijk nooit kwaad). Kijk hierbij goed naar de opbouw van myTree. Twee onderdelen zijn redelijk cruciaal:
- bij het aanmaken van elk element maak je bij dit element ook een children array aan, dit zit niet in jouw bovenstaande loop?
- tegelijkertijd voeg je het huidige element toe als child van de parent, laat dit even bezinken :p, op deze manier klik je de elementen aan elkaar als boom en om deze reden is het dus belangrijk dat je de items in de goede volgorde ophaalt, anders bestaan parents mogelijk nog niet in myTree
Met enige aanpassingen in jouw code zou je met behulp van mijn voorbeeld dit alles redelijk eenvoudig aan de praat moeten krijgen.
Gewijzigd op 06/02/2020 16:31:54 door Thomas van den Heuvel