Dynamické menu z databáze
- Altimit
- Člen | 82
Dobrý den, chci se zeptat jak by šla udělat určitá věc.
Mám udělanou databázi stylem:
id | name | hidden | autor | type | category_id |
---|---|---|---|---|---|
1 | polozka1 | 0 | 1 | menu | 0 |
2 | polozka2 | 0 | 1 | submenu | 1 |
3 | polozka3 | 0 | 1 | submenu | 1 |
Kdy name je název, hidden je nastavení, jest-li se má zobrazovat nebo skrývat, autor odkazuje na tabulku user_id, type určuje co to vlastně je a category_id má odkazovat na id.
Jedná se o to, že chci udělat menu, které má vypadat nějak takhle:
Jedna z podmínek zadavatelky byla, že chce mít možnost přidávat
další položky, jinak by jsem tohle neřešil.
Vím jak udělat ty normální menu, kdy v MenuControl mi načítá data
z databáze přes položku type = menu
, ale nastává problém že
nevím jak udělat to submenu, které se automaticky doplní do seznamu pod
položku menu a položka menu se změní na collapsible položku..
Nějaké nápady? děkuji.
- Kcko
- Člen | 470
Říká se tomu rekurze, prostě zanoříš block menu do menu. Někde to tu
bylo, ale je to lehké na napsání.
K té tvé struktuře, ukládej si ID rodičovské položky.
(Nejsnadněji pro tebe ⇒ https://latte.nette.org/cs/tags#…
„V bloku lze vložit i sebe sama, což lze použít např. pro vykreslení
stromového menu.“)
A to aby to bylo collapsible nemá s Nette nic společného, zařídíš
snadno přes JavaScript.
Editoval Kcko (21. 3. 2018 14:51)
- Altimit
- Člen | 82
@CZechBoY sorry, dodávám
MenuControl.php
public function render($id = NULL)
{
$this->template->setFile(__DIR__ . '/template.latte');
$db = $this->database->table('category')->where(' category_id IS NULL');
$this->template->menu = $db;
$this->template->render();
}
template.latte
<style>
.collapsible-body{
padding: 0!important;
}
</style>
<h5>Kategorie</h5>
{block #menu}
<ul class="collection white collapsible">
{foreach $menu as $item}
{php $selection = $item->related('category','category_id')}
{if $selection->count()>0}
{if $item->category_id === NULL}
<li>
<a class="center red-text collapsible-header">{$item->name} <i class="material-icons right" style="margin-right:0;">arrow_drop_down</i></a>
<div class="collapsible-body">
<ul>
{include #menu menu => $selection}
</ul>
</div>
</li>
{elseif $item->category_id !== NULL}
{/if}
{*{if $item->category_id === NULL}</ul>{elseif $item->category_id !== NULL}</li>{/if}
*}{include #menu menu => $selection}
{else}
<a class="red-text collection-item center-align" href="#{$item->name|webalize}-{$item->id}"><li>{$item->name}</li></a>
{/if}
{/foreach}
</ul>
{/block}
- Piticu
- Člen | 93
Co znamena ta podminka category_id IS NULL
? Nevim, zda pomaha
tvemu problemu, ale jsem zvedavy jaky ma vyznam :) Jinak mel by sis udelat
nejaky model pro vyber a filtrovani dat z db a nechat si latte jen pro
vykreslovani.
Muzes prosim ukazat si tabulku Category
?
Altimit napsal(a):
@CZechBoY sorry, dodávám
MenuControl.phppublic function render($id = NULL) { $this->template->setFile(__DIR__ . '/template.latte'); $db = $this->database->table('category')->where(' category_id IS NULL'); $this->template->menu = $db; $this->template->render(); }
template.latte
<style> .collapsible-body{ padding: 0!important; } </style> <h5>Kategorie</h5> {block #menu} <ul class="collection white collapsible"> {foreach $menu as $item} {php $selection = $item->related('category','category_id')} {if $selection->count()>0} {if $item->category_id === NULL} <li> <a class="center red-text collapsible-header">{$item->name} <i class="material-icons right" style="margin-right:0;">arrow_drop_down</i></a> <div class="collapsible-body"> <ul> {include #menu menu => $selection} </ul> </div> </li> {elseif $item->category_id !== NULL} {/if} {*{if $item->category_id === NULL}</ul>{elseif $item->category_id !== NULL}</li>{/if} *}{include #menu menu => $selection} {else} <a class="red-text collection-item center-align" href="#{$item->name|webalize}-{$item->id}"><li>{$item->name}</li></a> {/if} {/foreach} </ul> {/block}
Editoval Piticu (23. 3. 2018 8:05)
- Altimit
- Člen | 82
@Piticu Co přesněji jako myslíš? to co jsem psal hned v úvodu?
nebo chceš i data?…
tady je obojí opět.
Omlouvám se, že píšu tak pozdě, ale je to způsobené mojí
vytíženosti :)
Piticu napsal(a):
Co znamena ta podminka
category_id IS NULL
? Nevim, zda pomaha tvemu problemu, ale jsem zvedavy jaky ma vyznam :) Jinak mel by sis udelat nejaky model pro vyber a filtrovani dat z db a nechat si latte jen pro vykreslovani.
Muzes prosim ukazat si tabulkuCategory
?
- suwer
- Člen | 33
To reseni na strane kodu je cele trochu nestastne :-). V presenteru si vytahujes pouze top kategorie, v sablone pak odpalujes jeden select za druhym pro jejich podkategorie. A pred samotnym vykreslenim jeste znova kontrolujes, ze je to fakt top kategorie.
Vytahni si cele menu z db naraz a transformuj ho dle svych pozadavku do vice rozmerneho pole (nebo objektu). To pak predej do sablony a vykresli.
- Altimit
- Člen | 82
ale já vůbec nevím jak, jinak by jsem to tak udělal :D
Tohle co tam je tak je řešení už od někoho udělané…
:)
suwer napsal(a):
To reseni na strane kodu je cele trochu nestastne :-). V presenteru si vytahujes pouze top kategorie, v sablone pak odpalujes jeden select za druhym pro jejich podkategorie. A pred samotnym vykreslenim jeste znova kontrolujes, ze je to fakt top kategorie.
Vytahni si cele menu z db naraz a transformuj ho dle svych pozadavku do vice rozmerneho pole (nebo objektu). To pak predej do sablony a vykresli.
- Kcko
- Člen | 470
Altimit napsal(a):
ale já vůbec nevím jak, jinak by jsem to tak udělal :D
Tohle co tam je tak je řešení už od někoho udělané…
:)suwer napsal(a):
To reseni na strane kodu je cele trochu nestastne :-). V presenteru si vytahujes pouze top kategorie, v sablone pak odpalujes jeden select za druhym pro jejich podkategorie. A pred samotnym vykreslenim jeste znova kontrolujes, ze je to fakt top kategorie.
Vytahni si cele menu z db naraz a transformuj ho dle svych pozadavku do vice rozmerneho pole (nebo objektu). To pak predej do sablony a vykresli.
tak co třeba takhle (objektově)
<?php
$rootNode = new Node('ROOT');
$pcNode = new Node('pc');
$ntbNode = new Node('notebook');
$dellNode = new Node('dell');
$acerNode = new Node('acer');
$rootNode->add($ntbNode);
$rootNode->add($pcNode);
$ntbNode->add($dellNode);
$ntbNode->add($acerNode);
//echo showNode($rootNode);
echo "<pre>";
print_R($dellNode);
// echo "<pre>";
// print_R($rootNode);
echo showNodeCrumbs($dellNode);
function showNodeCrumbs($node)
{
if ($node->parent)
return showNodeCrumbs($node->parent) . ' / ' . $node->name;
else
return $node->name;
}
function showNode($node, $level = 0)
{
$out = '<ul>';
$out .= '<li>' . $node->name . " L " . $level;
if ($node->childrenTotal)
{
foreach ($node->children as $childNode)
{
$out .= showNode($childNode, $level + 1);
}
}
$out .= '</ul>';
return $out;
}
class Node
{
public $name;
public $children = [];
public $parent = NULL;
public $childrenTotal = 0;
public function __construct($name)
{
$this->name = $name;
}
public function add($node)
{
$this->children[] = $node;
$this->childrenTotal++;
$node->setParent($this);
return $this;
}
public function setParent($parent = NULL)
{
$this->parent = $parent;
return $this;
}
}
?>
nebo takhle (akorát tam proměnné odkrývám přes global, což je ekl, ale jde o to abych pochopil jak si to máš uložit a jak to rekurzivně projít, ve finále z toho můžeš udělat jednoduchou třídu a globální proměnné udělat jako členské proměnné třídy a bude to fungovat)
<?php
$tree = [
[1, 'Sport', 0],
[2, 'Letní', 1],
[3, 'Zimní', 1],
[4, 'Fotbal', 2],
[41, 'Amatéři', 4],
[42, 'Profíci', 4],
[420, 'A', 42],
[5545, 'B', 42],
[888, 'C', 42],
[8423388, 'C1', 888],
[5, 'Hokej', 3],
];
$parents = [];
$itemToParent = [];
foreach ($tree as $t)
{
$parents[$t[2]][] = $t[0];
$itemToParent[$t[0]] = $t[2];
}
$itemsHasParent = [];
if ($_GET['id'])
{
$id = $_GET['id'];
$itemsHasParent[] = $id;
while ($itemToParent[$id])
{
$itemsHasParent[] = $itemToParent[$id];
$id = $itemToParent[$id];
}
}
tree(0, FALSE, 0, 2);
tree(0, TRUE, 0, 4);
function tree($parentId, $openAlways = FALSE, $depth = 0, $maxDepth = 3)
{
global $tree;
global $itemsHasParent;
echo "<ul>";
foreach ($tree as $t)
{
if ($t[2] == $parentId)
{
echo "<li><a href='?id=".$t[0]."'>".$t[1]." d:$depth</a>";
if ( ((in_array($t[0], $itemsHasParent) && !$openAlways) || $openAlways) && $maxDepth > $depth)
tree($t[0], $openAlways, $depth + 1, $maxDepth);
}
}
echo "</ul>";
}
?>
A pak ještě tu http://lab.rjwebdesign.cz/tree (http://lab.rjwebdesign.cz/tree/index.phps), tam to mám obdobně přes nějakou trapnou třídu.
Editoval Kcko (29. 3. 2018 9:45)
- Piticu
- Člen | 93
Altimit napsal(a):
@Piticu Co přesněji jako myslíš? to co jsem psal hned v úvodu? nebo chceš i data?…
tady je obojí opět.
Omlouvám se, že píšu tak pozdě, ale je to způsobené mojí vytíženosti :)Piticu napsal(a):
Co znamena ta podminka
category_id IS NULL
? Nevim, zda pomaha tvemu problemu, ale jsem zvedavy jaky ma vyznam :) Jinak mel by sis udelat nejaky model pro vyber a filtrovani dat z db a nechat si latte jen pro vykreslovani.
Muzes prosim ukazat si tabulkuCategory
?
Nebylo by lepsi udelat si 2 tabulky? menu a submenu? v submenu bys mel id_menu a pomoci INNER JOIN bys ses dostal k oboum tabulkam :)
- GEpic
- Člen | 566
Stačí jedna tabulka která má závislost sama na sobě, kde prvek bude obsahovat parent_id (nadřazený prvek), to se potom dá pomocí related už zařídit celé. Začneš vypisovat prvky bez parenta a u toho si zjistíš, jestli náhodou tento prvek není parentem nějakému jinému. Tak můžeš udělat menu třeba desetistupňové.
Editoval GEpic (30. 3. 2018 9:58)