Unlimited multi level menu in mvc

สวัสดีค่ะวันนี้เรามาว่ากันเรื่องเมนูกันดีกว่านะคะ คำว่าเมนู ผู้เขียนคิดว่าทุกคนต้องรู้จักแน่นอน เพราะในการพัฒนาแต่ละระบบนั้นส่วนใหญ่จะมีส่วนของงานหลายๆส่วน ทำให้มีการออกแบบหน้าจอการใช้งานหลายหน้าจอเพื่อรองรับการทำงานของระบบนั้น เมื่อส่งมอบระบบ แน่นอน!! ค่ะ ความต้องการของลูกค้าไม่หยุดแค่นั้นแน่นอน เมื่อความต้องการเพิ่ม การทำงานของหน้าจอก็เพิ่ม เมนูก็ต้องเพิ่มตามมาเช่นกัน ทำให้ผู้พัฒนาต้องไปแก้โค้ดในส่วนของเมนูทุกครั้งที่มีการเพิ่มเมนู การจัดหมวดหมูของเมนู หรือต้องการปรับเปลี่ยน path ที่ไปเรียกหน้าจอนั้นๆ แค่คิดก็ดูยุ่งยากต่อการจัดการแล้ว วันนี้ผู้เขียนจึงนำวิธีการออกแบบและพัฒนาในส่วนของเมนูที่ผู้เขียนได้ใช้พัฒนาใน MVC มาเป็นตัวอย่างให้ดูกันนะคะ สำหรับผู้อ่านที่ไม่ได้ใช้ MVC ก็สามารถนำไปปรับเปลี่ยนได้ค่ะ หลังจากพัฒนาแล้วระบบก็จะสามารถ เพิ่มเมนู หรือเปลี่ยน path ของเมนู หรือ จัดการกลุ่มของเมนู ได้โดยไม่ต้อง publish ระบบ ทุกครั้งที่มีการแก้ไข ทำให้ง่ายและไม่เสียเวลาในการจัดการเลยค่ะ เรามาเริ่มกันเลยค่ะ ผู้เขียนขอแบ่งการพัฒนาเป็นสองส่วนนะคะ คือ
1.การพัฒนาในฐานข้อมูล : ในส่วนของการออกแบบฐานข้อมูลผู้อ่านต้องออกแบบให้มีการเก็บ id ของ parent เพื่อระบุให้รู้ว่าเมนูตัวนี้เป็นลูกของเมนูตัวไหน

ตัวอย่างการออกแบบฐานข้อมูลของเมนู

คอลัมภ์ คำอธิบาย
 ParentID Id ของ parent
MenuID Id ของเมนู
MenuName ชื่อของเมนู

2.การพัฒนาระบบ : เป็นการพัฒนาระบบผู้เขียนจะใช้วิธีการพัฒนาแบบใช้ Recursive เข้ามาจัดการในส่วนของการแสดงเมนู โดยข้อดีของ Recursive คือเราสามารถจัดการได้ทั้งส่วนที่มีเมนูย่อย และไม่มีเมนูย่อย

ตัวอย่างในส่วนของ Recursive ที่ใช้ใน View เพื่อการแสดงเมนู ( MVC)

@helper GetSubMenus(IEnumerable<menutable> siteMenu, Nullable<int> parentID)

{

    foreach (var i in Model.Where(a => a.ParentID.Equals(parentID)))

    {

        var submenu = Model.Where(a => a.ParentID.Equals(i.MenuID)).Count();

 

        <li class=”@(submenu > 0 ? “dropdown-submenu” : “dropdown”)”>

            <a href=”@(!string.IsNullOrEmpty(i.MenuLink) ? Url.Content(i.MenuLink) : “~/default)” style=”font-size:16px;”>@i.MenuName</a>

            @if (submenu > 0)

            {

                <ul class=”dropdown-menu”>

                    @GetSubMenus(siteMenu, i.MenuID)

                    @* Recursive  Call for Populate Sub items here*@

                </ul>

            }

        </li>

    }

}

 

@{

    var mymenu = @Model;

    var menuParentID = mymenu.First().ParentID;

@if (mymenu != null && mymenu.Count() > 0)

{

    <nav class=”navbar navbar-default”>

        <div class=”container-fluid”>

            <div class=”collapse navbar-collapse” id=”bs-example-navbar-collapse-1″>

                <ul class=” nav navbar-nav”>

                    @GetSubMenus(mymenu, menuParentID)

                </ul>

            </div>

        </div>

    </nav>

}

ตัวอย่างหน้าจอของเมนูที่เรียกใช้ Recursive เพื่อจัดการเมนู

จากรูปจะเป็นตัวอย่างของเมนูที่มีเมนูย่อย โดยมีเมนูหลักเป็น Parent ในรูป คือ testsub2 โดยมีลูก(Child) เป็น jar2 และ jar และ jar ก็เป็น Parent โดยมี testSub เป็นลูก(Child) อีกครั้ง จะเห็นว่าไม่ว่าจะต้องการให้มีเมนูย่อยแค่ไหน Recursive ก็สามารถทำเราง่ายในการจัดการมากขึ้น โดยไม่ต้องมา copy code วางหลายๆครั้งให้ยุ่งยากอีกต่อไปค่ะ และที่สำคัญในตัวอย่างเราจะดึงข้อมูลเมนูมาจากฐานข้อมูล ไม่ว่าเราจะเพิ่มเมนู หรือเปลี่ยน path หรือเพิ่มเมนูย่อยในเมนูหลักลงลึกแค่ไหน เราก็ไม่ต้องมาเสียเวลานั่งแก้โค้ดในหน้าของเมนูอีกต่อไปแล้วนะคะ ผู้อ่านท่านใดมีการจัดเมนูหลายเมนู ลองนำไปปรับใช้กันดูนะคะ ขอบคุณค่ะ^^

 

 

 

แหล่งอ้างอิง

https://stackoverflow.com/questions/35326302/unlimited-multi-level-menu-in-mvc