如何在MVC中基于带父子关系的JSON数据创建带复选框树形结构
Let's tackle your two main issues: building a proper nested tree structure and combining those two $.each loops. The root problem with your current code is that you're appending both domains and modules directly to the same root list, resulting in a flat structure instead of parent-child nesting. Here's how to fix it:
Step 1: Adjust Frontend JavaScript Logic
We'll first group modules by their associated DomainID (so we can quickly find which modules belong to which domain), then loop through domains and nest their corresponding modules directly under them. This merges both loops into a single logical flow.
function GetSelectedDomainValue(DomainID) { var adminID = jQuery('[id$=hdnAdminID]').val(); var roleID = $("#RoleID").val(); var domainID = $("#DomainID").val(); $.ajax({ type: 'POST', url: '@Url.Action("BindDomainUserAccess")', dataType: 'json', data: { RoleID: roleID, DomainID: domainID, AdminID: adminID }, success: function (data) { // 1. Clear existing tree content first to avoid duplicates $("#tree").empty(); // 2. Group modules by DomainID for quick lookup const modulesByDomain = {}; data.ModuleUserViews.forEach(module => { if (!modulesByDomain[module.DomainID]) { modulesByDomain[module.DomainID] = []; } modulesByDomain[module.DomainID].push(module); }); // 3. Loop through domains and build nested structure data.DomainUserViews.forEach(domain => { // Create parent domain li with checkbox, name, and empty sub-list const domainLi = $(` <li class="dd-item"> <a href="#"> <input type='checkbox' id='${domain.DomainID}' name='DomainUserViews' class='my_chkBox' /> ${domain.DomainName} </a> <ul class="dd-list"></ul> </li> `); // Add corresponding modules to the domain's sub-list const domainModules = modulesByDomain[domain.DomainID] || []; domainModules.forEach(module => { const moduleLi = $(` <li class="dd-item"> <a href="#"> <input type='checkbox' id='${module.ModuleID}' name='ModuleUserViews' class='my_chkBox' /> ${module.ModuleName} </a> </li> `); domainLi.find('.dd-list').append(moduleLi); }); // Append the complete domain node to the root tree $("#tree").append(domainLi); }); }, error: function (ex) { alert('Failed to retrieve access data : ' + ex); } }); }
Step 2: Verify Backend Data Structure
Make sure your ViewRoleModules class (returned by GetRolesDomainModules) includes a DomainID property that matches the DomainID from DomainView. This is critical for grouping modules under their parent domains. If it doesn't exist, update your backend class:
// Ensure ViewRoleModules has a DomainID property to link with parent domains public class ViewRoleModules { public int ModuleID { get; set; } public string ModuleName { get; set; } public int DomainID { get; set; } // Add this if missing // Other existing properties... }
Key Improvements Explained:
- Nested Tree Structure: Each domain now has its own child
<ul>where we insert its associated modules, creating the parent-child hierarchy you want (e.g., Doctor → Add/View). - Merged Loops: We no longer need separate loops for domains and modules. Instead, we first organize modules by domain, then build the entire tree in one pass through the domains.
- Better Performance: Using jQuery to build elements before appending reduces repeated DOM updates, making the code more efficient.
- Clean State: We clear the tree before adding new content to avoid stacking old data when the function runs multiple times.
HTML Remains Unchanged
Your existing HTML structure works perfectly with this new logic—we're just leveraging the nested dd-list class to build the hierarchy.
内容的提问来源于stack exchange,提问作者Ivin Raj

