Tree categories in offcanvas

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.

1 Like

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.