From 6bb96eda8548d68fdbbbd778b21c791c6a05ff22 Mon Sep 17 00:00:00 2001 From: Lucas da Silva Nishikawara Date: Fri, 7 Apr 2023 21:37:59 -0300 Subject: [PATCH] Add TreeModelBinder to retrieve treeview data; Add property to check if item was selected; Add sql script with table update --- TreeViewInMVC/App_Data/database-20230407.sql | Bin 0 -> 23728 bytes TreeViewInMVC/Binders/TreeModelBinder.cs | 68 +++++++++++++++++++ TreeViewInMVC/Controllers/HomeController.cs | 10 ++- TreeViewInMVC/Global.asax.cs | 4 ++ TreeViewInMVC/Models/IdentityModels.cs | 6 ++ TreeViewInMVC/Models/Tree.cs | 50 +++++++++++++- TreeViewInMVC/Models/TreeModel.cs | 1 + TreeViewInMVC/TreeViewInMVC.csproj | 2 + TreeViewInMVC/Views/Home/TreeView.cshtml | 60 ++++++++++++---- 9 files changed, 183 insertions(+), 18 deletions(-) create mode 100644 TreeViewInMVC/App_Data/database-20230407.sql create mode 100644 TreeViewInMVC/Binders/TreeModelBinder.cs diff --git a/TreeViewInMVC/App_Data/database-20230407.sql b/TreeViewInMVC/App_Data/database-20230407.sql new file mode 100644 index 0000000000000000000000000000000000000000..4fdef4fd80fc58bdc80ac6158c9e7066a6118e57 GIT binary patch literal 23728 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 literal 0 HcmV?d00001 diff --git a/TreeViewInMVC/Binders/TreeModelBinder.cs b/TreeViewInMVC/Binders/TreeModelBinder.cs new file mode 100644 index 0000000..0b180f7 --- /dev/null +++ b/TreeViewInMVC/Binders/TreeModelBinder.cs @@ -0,0 +1,68 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Web; +using System.Web.Mvc; +using TreeViewInMVC.Models; +using Newtonsoft.Json; + +namespace TreeViewInMVC.Binders +{ + public class TreeModelBinder : IModelBinder + { + public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) + { + HttpRequestBase request = controllerContext.HttpContext.Request; + + var listTreeHidden = JsonConvert.DeserializeObject>(request.Form.Get("treeHidden")); + + if (listTreeHidden.Count > 0) + { + var selectedIds = JsonConvert.DeserializeObject>(request.Form.Get("treeHiddenSelected")); + + if (selectedIds.Count > 0) + { + for (int i = 0; i < listTreeHidden.Count; i++) + { + if (selectedIds.Contains(listTreeHidden[i].Id)) + listTreeHidden[i].Selected = true; + } + + } + + if (listTreeHidden.Count > 1) + { + var listWithoutParentId = listTreeHidden.Where(x => x.ParentId == null).ToList(); + + var newlist = new List(); + + for (int i = 0; i < listWithoutParentId.Count; i++) + { + newlist.Add(OrganizeChildrenItems(listWithoutParentId[i], ref listTreeHidden)); + } + + listTreeHidden = newlist; + + } + } + + return listTreeHidden; + } + + TreeModel OrganizeChildrenItems(TreeModel item, ref List list) + { + if (!list.Any(x => x.ParentId == item.Id)) + return item; + + if (item.Childs == null) + item.Childs = new List(); + + foreach (TreeModel child in list.Where(x => x.ParentId == item.Id)) + { + item.Childs.Add(OrganizeChildrenItems(child, ref list)); + } + + return item; + } + } +} \ No newline at end of file diff --git a/TreeViewInMVC/Controllers/HomeController.cs b/TreeViewInMVC/Controllers/HomeController.cs index 2fa298f..7d4f844 100644 --- a/TreeViewInMVC/Controllers/HomeController.cs +++ b/TreeViewInMVC/Controllers/HomeController.cs @@ -1,7 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Web; using System.Web.Mvc; using TreeViewInMVC.Models; @@ -34,5 +32,11 @@ public ActionResult TreeView() return View(db.TreeModel.Where(x => !x.ParentId.HasValue).ToList()); } + [HttpPost] + public ActionResult TreeView(List model) + { + return View(model); + } + } } \ No newline at end of file diff --git a/TreeViewInMVC/Global.asax.cs b/TreeViewInMVC/Global.asax.cs index 737a0bd..74bf7f7 100644 --- a/TreeViewInMVC/Global.asax.cs +++ b/TreeViewInMVC/Global.asax.cs @@ -5,6 +5,8 @@ using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; +using TreeViewInMVC.Binders; +using TreeViewInMVC.Models; namespace TreeViewInMVC { @@ -16,6 +18,8 @@ protected void Application_Start() FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); + + ModelBinders.Binders.Add(typeof(List), new TreeModelBinder()); } } } diff --git a/TreeViewInMVC/Models/IdentityModels.cs b/TreeViewInMVC/Models/IdentityModels.cs index 538c22d..5901b4a 100644 --- a/TreeViewInMVC/Models/IdentityModels.cs +++ b/TreeViewInMVC/Models/IdentityModels.cs @@ -25,6 +25,12 @@ public ApplicationDbContext() { } + protected override void OnModelCreating(DbModelBuilder modelBuilder) + { + Database.SetInitializer(null); + base.OnModelCreating(modelBuilder); + } + public static ApplicationDbContext Create() { return new ApplicationDbContext(); diff --git a/TreeViewInMVC/Models/Tree.cs b/TreeViewInMVC/Models/Tree.cs index bebb65c..6aa78f3 100644 --- a/TreeViewInMVC/Models/Tree.cs +++ b/TreeViewInMVC/Models/Tree.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Reflection; +using System.Reflection.Emit; using System.Web; using System.Web.Mvc; using System.Web.UI; @@ -152,6 +153,9 @@ public override string ToString() var listItems = _items.ToList(); + var div = new TagBuilder("div"); + div.MergeAttribute("id", "jstree"); + var ul = new TagBuilder("ul"); ul.MergeAttributes(_htmlAttributes); var li = new TagBuilder("li") @@ -173,12 +177,41 @@ public override string ToString() } ul.InnerHtml += li.ToString(); - return ul.ToString(); + div.InnerHtml += ul.ToString(); + + var outerDiv = new TagBuilder("div"); + outerDiv.InnerHtml += div.ToString(); + + var hiddenTreeData = new TagBuilder("input"); + hiddenTreeData.MergeAttribute("id", "treeHidden"); + hiddenTreeData.MergeAttribute("name", "treeHidden"); + hiddenTreeData.MergeAttribute("type", "hidden"); + hiddenTreeData.MergeAttribute("value", ""); + + outerDiv.InnerHtml += hiddenTreeData.ToString(); + + var hiddenTreeIdsSelecteds = new TagBuilder("input"); + hiddenTreeIdsSelecteds.MergeAttribute("id", "treeHiddenSelected"); + hiddenTreeIdsSelecteds.MergeAttribute("name", "treeHiddenSelected"); + hiddenTreeIdsSelecteds.MergeAttribute("type", "hidden"); + hiddenTreeIdsSelecteds.MergeAttribute("value", ""); + + outerDiv.InnerHtml += hiddenTreeIdsSelecteds.ToString(); + + return outerDiv.ToString(); } private void AppendChildren(TagBuilder parentTag, T parentItem, Func> childrenProperty) { - var children = childrenProperty(parentItem).ToList(); + + var enumerableList = childrenProperty(parentItem); + + if (enumerableList == null) + { + return; + } + + var children = enumerableList.ToList(); if (!children.Any()) { return; @@ -215,12 +248,25 @@ private TagBuilder GetLi(T item) { if (prop.Name.ToLower() == "id") li.MergeAttribute("id", prop.GetValue(item, null).ToString()); + + if (prop.Name.ToLower() == "title") + li.MergeAttribute("data-title", prop.GetValue(item, null).ToString()); + + if (prop.Name.ToLower() == "description") + li.MergeAttribute("data-description", prop.GetValue(item, null) == null ? "" : prop.GetValue(item, null).ToString()); + + if (prop.Name.ToLower() == "parentid") + li.MergeAttribute("data-parentId", prop.GetValue(item, null) == null ? "" : prop.GetValue(item, null).ToString()); + //li.GenerateId(prop.GetValue(item, null).ToString()); //object propValue = prop.GetValue(myObject, null); // Do something with propValue if (prop.Name.ToLower() == "sortorder") li.MergeAttribute("priority", prop.GetValue(item, null).ToString()); } + + li.MergeAttribute("treeJsElement", "treeJsElement"); + return li; } } diff --git a/TreeViewInMVC/Models/TreeModel.cs b/TreeViewInMVC/Models/TreeModel.cs index 3119823..6c69c9d 100644 --- a/TreeViewInMVC/Models/TreeModel.cs +++ b/TreeViewInMVC/Models/TreeModel.cs @@ -9,6 +9,7 @@ public class TreeModel public string Title { get; set; } public string Description { get; set; } public int? ParentId { get; set; } + public bool Selected { get; set; } [ForeignKey("ParentId")] public virtual TreeModel Parent { get; set; } public virtual ICollection Childs { get; set; } diff --git a/TreeViewInMVC/TreeViewInMVC.csproj b/TreeViewInMVC/TreeViewInMVC.csproj index e246f2f..0222b93 100644 --- a/TreeViewInMVC/TreeViewInMVC.csproj +++ b/TreeViewInMVC/TreeViewInMVC.csproj @@ -25,6 +25,7 @@ + true @@ -167,6 +168,7 @@ + diff --git a/TreeViewInMVC/Views/Home/TreeView.cshtml b/TreeViewInMVC/Views/Home/TreeView.cshtml index 134c65b..e4c259a 100644 --- a/TreeViewInMVC/Views/Home/TreeView.cshtml +++ b/TreeViewInMVC/Views/Home/TreeView.cshtml @@ -4,19 +4,22 @@

TreeView

-
+
+ @*
*@ @(Html.TreeView(Model) - .EmptyContent("root") - .Children(m => m.Childs) - .HtmlAttributes(new { id = "tree" }) - .ChildrenHtmlAttributes(new { @class = "subItem" }) - .ItemText(m => m.Title) - .ItemTemplate( - @ - @item.Title - ) + .EmptyContent("root") + .Children(m => m.Childs) + .HtmlAttributes(new { id = "tree" }) + .ChildrenHtmlAttributes(new { @class = "subItem" }) + .ItemText(m => m.Description) + .ItemTemplate( + @ + @item.Title + ) ) -
+ @*
*@ + +
@section scripts { @@ -43,8 +46,39 @@ "icon": "fa fa-file icon-state-warning icon-lg" } }, - "plugins": ["dnd", "state", "types", "sort", "checkbox"] + "plugins": ["dnd", "state", "types", "sort", "checkbox"], + }); + + $('#jstree').on('changed.jstree', function (e, data) { + var i, j, r = [], m = []; + for (i = 0, j = data.selected.length; i < j; i++) { + r.push(data.instance.get_node(data.selected[i]).id); + } + + $('#treeHiddenSelected').val(JSON.stringify(r)); + }); + }); - + + let list = $("li[treejselement='treeJsElement']").map(function () { return $(this).attr("id"); }).get(); + + var elem = {}, n = []; + + if (list.length > 0) { + + for (var i = 0; i < list.length; i++) { + elem = $("li#" + list[i] + "[treejselement='treeJsElement']"); + n.push({ + Id: list[i], + Title: elem.data("title"), + Description: elem.data("description"), + ParentId: elem.data("parentid") + }); + } + + $('#treeHidden').val(JSON.stringify(n)); + } + + }