How to make hierarchical tree (3 levels) categories in offcanvas from sql data id,parentId,level
You can simply use ul>li structure, with nested uls or any nested div structure for that.
Teodor , from serverconnect data like id name parentId level
a24825f4-88a6-4e92-bf58-ec406244ebdb coffee c530d0b0-605a-4e89-a630-333ccbd92729 2 for me unclear how to fill offcanvas .Can you advise in some details
Yes, you can create a repeat region and nest another one inside it, like:
<ul is="dmx-repeat" id="repeat1" dmx-bind:repeat="your_expression">Main level
<li>Item
<ul is="dmx-repeat" id="repeat2" dmx-bind:repeat="your_expression">Sub Level
<li>Sub Item</li>
</ul>
</li>
</ul>
Maybe post what you have now and how the data is nested, so we can help further.
id | name | parentId | level | has_children |
---|---|---|---|---|
15dec69d-401e-4fe0-8855-8cbd45eaf9a2 | ХОЛОДНЫЕ ЗАКУСКИ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
215e683a-f90b-4384-a086-af72392eddf4 | СМУЗИ | c530d0b0-605a-4e89-a630-333ccbd92729 | 2 | 0 |
2d558a68-41fe-45dd-97d6-a41e185f8a87 | БУРГЕРЫ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
32921d01-615e-4bd3-8d59-bd81c668eadb | САЛАТЫ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
3afe39dc-963a-4568-b3ad-b7e869051c0e | БОУЛЫ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
4f3fa490-011e-4519-8cd3-864822e70dbc | ГАРНИРЫ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
82d23d92-7ca8-42b2-ad1e-c7f9d6dfb1b0 | ГОРЯЧИЕ ЗАКУСКИ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
88528169-4178-4cb9-a877-24fedf1173e5 | ПАСТА | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
8ebd13f8-a0dc-4a6e-a622-82af63efdb1b | ПП ПИТАНИЕ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
917d9bc2-dad4-4246-9ace-e80559de0108 | ОСНОВНЫЕ БЛЮДА | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
9774c757-2980-4c70-9c2a-e0036ddde585 | МИЛКШЕЙКИ | c530d0b0-605a-4e89-a630-333ccbd92729 | 2 | 0 |
9c00fdc3-afe2-49da-97c1-28711a849519 | СОК ФРЕШ | c530d0b0-605a-4e89-a630-333ccbd92729 | 2 | 0 |
b9edcd88-223f-4780-a2ba-4168387ae89a | ЗАВТРАКИ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
c53102ec-a10e-4a07-9ecf-e95696630fad | ПЕРВЫЕ БЛЮДА | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
c94518cc-b65c-46f1-aa08-fc68f119eb42 | Лимонады | c530d0b0-605a-4e89-a630-333ccbd92729 | 2 | 0 |
cc66dda1-887a-4a22-b57d-a877760ad213 | ДЕТСКОЕ МЕНЮ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
cd0b4550-5be3-44be-9e96-56c634a16be2 | ХЛЕБ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
d7a55454-e928-496e-8505-f3c6bc431c77 | ДЕСЕРТЫ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
de071a42-2a03-4a44-b9c0-66b4f8b956d8 | СОКИ, ПЕПСИ | c530d0b0-605a-4e89-a630-333ccbd92729 | 2 | 0 |
ea88ead7-2e2f-4bfc-a15a-4d2ab7e61bb8 | НЕАПОЛИТАНСКАЯ ПИЦЦА | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 0 |
17ed2376-94da-4e5f-a557-1de11a7e485e | Роллы | 1f94238a-274f-4e68-aec1-7894a8b8b36c | 3 | 0 |
231ee005-f9ea-4d9a-9f79-f3e717149d7c | Авторский чай | 7a0e49b3-653e-4301-ac03-1f746a6a85bf | 3 | 0 |
349fd81e-8950-4e3f-8dc8-456e88e5bea2 | ХОЛОДНЫЙ КОФЕ | a24825f4-88a6-4e92-bf58-ec406244ebdb | 3 | 0 |
4bce4e7c-db27-4f10-9919-dc5dcfdb73ee | Горячие | 1f94238a-274f-4e68-aec1-7894a8b8b36c | 3 | 0 |
6e212893-0bc4-4f16-9e6b-bce9769e7526 | Гунканы | 1f94238a-274f-4e68-aec1-7894a8b8b36c | 3 | 0 |
c530d0b0-605a-4e89-a630-333ccbd92729 | Бар | NULL | 1 | 1 |
c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | КУХНЯ | NULL | 1 | 1 |
1f94238a-274f-4e68-aec1-7894a8b8b36c | ЯПОНИЯ | c5932e0b-bda3-4eed-8c73-fbd4ab0cdbbb | 2 | 1 |
7a0e49b3-653e-4301-ac03-1f746a6a85bf | ЧАЙ | c530d0b0-605a-4e89-a630-333ccbd92729 | 2 | 1 |
a24825f4-88a6-4e92-bf58-ec406244ebdb | КОФЕ | c530d0b0-605a-4e89-a630-333ccbd92729 | 2 | 1 |
Sorry but your answer doesn't really help me.
Please explain in details what do you have on the page and what needs to be achieved. Check the code i posted.

Please find enclosed the page where offcanvas contains categories of menu items for restaurant . If you need some more details let me know
(Attachment test.html is missing)

(attachments)
test.html.zip (2.11 KB)
What to look at into this file?
Most of the code there is not really correct.
How about explaining what data do you return from the server action, how, and what do you want to do with it on the front end?
this sql WITH RECURSIVE CategoryTree AS (
SELECT
id,
name,
parentId,
1 AS level,
EXISTS(SELECT 1 FROM category c WHERE c.parentId = cat.id) AS has_children
FROM category cat
WHERE parentId IS NULL
UNION ALL
SELECT
c.id,
c.name,
c.parentId,
ct.level + 1,
EXISTS(SELECT 1 FROM category cc WHERE cc.parentId = c.id)
FROM category c
INNER JOIN CategoryTree ct ON c.parentId = ct.id
)
SELECT * FROM CategoryTree
ORDER BY level, parentId, name;
make data to srvcategory . what I need is to make offcanvas that will display categories of menu and user can select menu items byclicking the category
What is the result that is returned from this server action? Post a screenshot of the query results when you run the server action in the browser.
If i have the data received by the server action in this format, then i would probably do it like:
<ul class="menu-level-1" is="dmx-repeat" id="repeat1" dmx-bind:repeat="serverconnect1.data.query.data.filter(`level==1`)">
<li>
<dmx-value id="getParentId" dmx-bind:value="id"></dmx-value>
<a href="#">{{name}}</a>
<ul class="menu-level-2" is="dmx-repeat" id="repeat2" dmx-bind:repeat="serverconnect1.data.query.data.filter(`parentId==getParentId.value`)">
<li>
<dmx-value id="getParentId" dmx-bind:value="id"></dmx-value>
<a href="#">{{name}}</a>
<ul class="menu-level-3" is="dmx-repeat" id="repeat3" dmx-bind:repeat="serverconnect1.data.query.data.filter(`parentId==getParentId.value`)">
<li>
<a href="#">{{name}}</a>
</li>
</ul>
</li>
</ul>
</li>
</ul>
I would prefer nesting the data on the server side and sending the nested data from there like explained here: Nested Repeat Regions
Thank you.Regarding server side the problem is that data is coming from API r_keeper. But I will think about
I made the following offcanvas tree
<div class="offcanvas-body p-0">
<!-- Уровень 1 -->
<ul class="list-unstyled mb-0" is="dmx-repeat" dmx-bind:repeat="srvcategory.data.custom.where('parentId', null, '==')">
<li class="menu-item">
<li class="menu-item">
<a href="#" class="d-flex align-items-center px-4 py-2 text-dark text-decoration-none hover-bg-light" dmx-on:click="has_children ? 1 : srvmenu.load({category_id: id}), offcanvas.toggle()">
<span class="flex-grow-1">{{level1}}</span>
<span dmx-show="has_children" class="ms-2 arrow text-muted">▸</span>
</a>
<!-- Уровень 2 -->
<ul class="list-unstyled bg-light-subtle" is="dmx-repeat" dmx-bind:repeat="srvcategory.data.custom.where('parentId', id, '==')">
<li class="menu-item">
<a href="#" class="d-flex align-items-center px-4 py-2 text-dark text-decoration-none hover-bg-light" dmx-on:click="has_children ? 1 : srvmenu.load({category_id: id}), offcanvas.toggle()">
<span class="flex-grow-1">{{level2}}</span>
<span dmx-show="has_children" class="ms-2 arrow text-muted">▸</span>
</a>
<!-- Уровень 3 -->
<ul class="list-unstyled bg-white" is="dmx-repeat" dmx-bind:repeat="srvcategory.data.custom.where('parentId', parent.id, '==')">
<li>
<a href="#" class="d-block px-4 py-2 text-dark text-decoration-none hover-primary" dmx-on:click="srvmenu.load({category_id: id}), offcanvas.toggle()">
<i class="bi bi-chevron-right me-2 text-muted"></i>
{{level3}}
</a>
</li>
</ul>
</li>
</ul>
</li>
</li>
</ul>
</div>
the problem is how to close and open tree branches
You can use either a nav component or collapse component for this.
Teodor, I will appreciate if you will show bow to apply in my case
And example i can provide, based on my previous example:
<ul class="menu-level-1" is="dmx-repeat" id="repeat1" dmx-bind:repeat="serverconnect1.data.query.data.filter(`level==1`)">
<li>
<dmx-value id="getParentId" dmx-bind:value="id"></dmx-value>
<a href="#" dmx-bind:data-bs-toggle="has_children ? 'collapse' : ''" dmx-bind:data-bs-target="'#collapse-level-2-' + id" aria-expanded="false" dmx-bind:aria-controls="'collapse-level-2-' + id">
{{name}}
<i dmx-show="has_children" class="fas fa-chevron-down ms-2"></i>
</a>
<div class="collapse" dmx-bind:id="'collapse-level-2-' + id">
<ul class="menu-level-2" is="dmx-repeat" id="repeat2" dmx-bind:repeat="serverconnect1.data.query.data.filter(`parentId==getParentId.value`)">
<li>
<dmx-value id="getParentId2" dmx-bind:value="id"></dmx-value>
<a href="#" dmx-bind:data-bs-toggle="has_children ? 'collapse' : ''" dmx-bind:data-bs-target="'#collapse-level-3-' + id" aria-expanded="false" dmx-bind:aria-controls="'collapse-level-3-' + id">
{{name}}
<i dmx-show="has_children" class="fas fa-chevron-down ms-2"></i>
</a>
<div class="collapse" dmx-bind:id="'collapse-level-3-' + id">
<ul class="menu-level-3" is="dmx-repeat" id="repeat3" dmx-bind:repeat="serverconnect1.data.query.data.filter(`parentId==getParentId2.value`)">
<li class="menu-item-level-3">
<a href="#">{{name}}</a>
</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
</ul>
If you need any further customization you would need to do that yourself. This stuff is not supported in Wappler as a component out of the box.