View that add items to nested list within nested list - c#

I have a fairly simple example model that contains a list, which also contains a list.
// Main object ... 1
public class TestModel
{
public int Id { get; set; }
public string Name { get; set; }
// 0..*
public IList<Item> Items { get; set;}
}
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
// 0..*
public IList<SubItem> SubItems {get;set;}
}
public class SubItem
{
public int Id { get; set; }
public string Name { get; set; }
}
With these model classes, I would like to create a view which allow to dynamically add items and sub-items.
Example:
I have read a lot about this, but there does not seem to be a common method to perform what I want to do. There are lots of examples of a list within an object, but none about a list within a list within an object.
Is there a way to do what I want to do? Or do I absolutely need to separate my views?
What I've tried :
EditorTemplate (It works for my items list, but I can't add items to my SubItems list)
EditorFor (model => model.SubItems)
Add items with jQuery but I don't think it's the right way to do this.
Thanks,
S.H

This is possible, but the tricky part is getting the id's of your nested view controls to play nicely with the MVC model binder.
I've got this to work in the past by using the instructions detailed here --> http://mleeb.wordpress.com/2013/11/23/editing-nested-lists-in-asp-mvc-4/

Related

how to fill DataGridView with json lis

Hi I am using this function to show json in DataGridView but the problem is I have a list in the json file , this list doesn't display data in the grid
void show_data()
{
dataGrid.Columns.Clear();
dataGrid.DataSource = all_date;
}
my json file is as this
[{"Name":"350SC250-14","Fy":33.0,"GFy":false,"T":0.0713,"GT":false,"D":2.5,"Stud_D":1.5,"C":0.0,"B":3.5,"GB":false,"Manufacturer":"BIDDLE","CFS_File":"350SC250-14.cfss","Sub_SectionCount":0,"Sub_Section1":"","Sub_Section2":"","Sub_Section3":"","SectionType":3,"Configuration":0,"SectionParts":[{"Length":0.375,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":3.0,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":2.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":3.0,"Radius":0.1069},{"Length":0.5,"Radius":0.1069},{"Length":0.375,"Radius":0.0}]}]
my class is bellow
class dataForm
{
public string Name { get; set; }
public double Fy { get; set; }
public bool GFy { get; set; }
public double T { get; set; }
public bool GT { get; set; }
public double D { get; set; }
public double Stud_D { get; set; }
public double C { get; set; }
public double B { get; set; }
public bool GB { get; set; }
public string Manufacturer { get; set; }
public string CFS_File { get; set; }
public int Sub_SectionCount { get; set; }
public string Sub_Section1 { get; set; }
public string Sub_Section2 { get; set; }
public string Sub_Section3 { get; set; }
public int SectionType { get; set; }
public int Configuration { get; set; }
public List<SectionPart> SectionParts { get; set; }
}
class SectionPart
{
public double Length { get; set; }
public double Radius { get; set; }
}
so how can I diplay this sectionPart list ?
Add Newtonsoft.Json nuget :Install-Package Newtonsoft.Json to your project, and convert JSON to object using DeserializeObject
string data_from_json = #"[{'Name':'350SC250 - 14','Fy':33.0,'GFy':false,'T':0.0713,'GT':false,'D':2.5,'Stud_D':1.5,'C':0.0,'B':3.5,'GB':false,'Manufacturer':'BIDDLE','CFS_File':'350SC250 - 14.cfss','Sub_SectionCount':0,'Sub_Section1':'','Sub_Section2':'','Sub_Section3':'','SectionType':3,'Configuration':0,'SectionParts':[{'Length':0.375,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':3.0,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':2.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':3.0,'Radius':0.1069},{'Length':0.5,'Radius':0.1069},{'Length':0.375,'Radius':0.0}]}]";
dataGrid.Columns.Clear();
List<dataForm> all_date = JsonConvert.DeserializeObject<List<dataForm>>(data_from_json);
dataGrid.DataSource = all_date;
to display SectionParts only:
dataGrid.DataSource = all_date[0].SectionParts;
The problem you describe does not really have anything to do with JSON. The problem is with the Class dataForm. I do not like to say “problem” since the issue is fairly easy to understand, once you understand what your code is asking from the grid. The issue is that when the grid is given a DataSource like a List<T> or List<dataForm>, the grid will obligingly map each “primitive” property of the dataForm class (or any class T) to a column in the grid.
The grid is going to have to do something different when it comes across a property in the class that is a “Collection” or another “Class”. In this case, dataForm has a “collection” property …
public List<SectionPart> SectionParts { get; set; }
In this case the grid is not sophisticated enough to figure this out. It really is not going to know how to put “multiple” values into a single cell. Therefore, the grid will ignore collections as you obviously already know. This same Idea applies if the property in the class is another class… it will not display it.
Bear in mind, as other have commented, there are third-party controls that may have features that will show the collections or classes. Unfortunately, the out of the box DataGridView is fairly limited. In most cases, the easiest way to deal with this is in a “Master/Detail” type display, where the first grid displays the class and the second grid displays the collection of the “selected” item in the first grid.
With that said, there are ways to achieve your goal without a lot of work depending on “how” you want to “display” the data to the user. IMHO a master-detail is usually the easiest to implement and is user friendly. Another option, is to “flatten” each of the items in the collection creating a column(s) for each item in the collection. This is much more work and you will possibly end up with many columns and many empty cells… not user friendly. The last option which may work for your case is to create a public property in the dataForm class that “exposes” the SectionParts collection as a single string.
Example: in this case, the SectionPart class has two (2) properties.
public double Length { get; set; }
public double Radius { get; set; }
To help later, let’s override the ToString method to return the two values as a single string. Something like…
public override string ToString() {
return "L: " + Length + " R: " + Radius;
}
Moving to the dataForm class there is a “collection” of the SectionPart objects. To display ALL the section parts into a single cell we need to create a single string from ALL the section parts. Each part will be on a single line using the SectionParts ToString method we added above. To make this “single” string display in the grid, we need to add a new property to the dataForm class that returns this “list of parts” as a single string. This property may look like…
public string SectionPartsList {
get {
StringBuilder sb = new StringBuilder();
foreach (SectionPart sp in SectionParts) {
sb.AppendLine(sp.ToString());
}
return sb.ToString();
}
}.
You may need to adjust the grids rows height to accommodate, however, in my test, if you simply hover your cursor over the cell the list will display.
Lastly, for completeness, let us assume, that instead of a “List” of SectionParts the class had a single instance of this class.
public SectionPart SingleSectionPart { get; set; }
Again the grid is going to ignore this “class” property when creating the columns in the grid. However, if you wanted those two fields displayed in the grid, then it would be fairly simple to create two properties in the dataForm class that simply return those values. In this case, the two properties may look like…
public double SP_L {
get {
return SingleSectionPart.Length;
}
}
public double SP_R {
get {
return SingleSectionPart.Radius;
}
}
I hope this makes sense and helps.

Recursively Create a Menu using two Lists

I'm having trouble making a dynamic menu using ASP.NET MVC where the menu is organized according to your Groups in Active Directory. To cut through useless details, I have retrieved two lists: one gives me all the folders of the menu, the other gives me all the files. How would one go about recursively creating the menu, knowing that folders can have subfolders, and subsubfolders and so on? In my project they are called I have two models DocumentModel and CategoryModel as follows :
//Files
public class DocumentModel
{
public long iDDocument { get; set; }
public long iDCategory { get; set; }
public string docName { get; set; }
public string link { get; set; }
public string type { get; set; }
}
//Folders
public class CategoryModel
{
public long iDCategory { get; set; }
public string nom { get; set; }
public int iDParentCategory { get; set; }
}
I then pass them to my view using a bigger model:
public class CatDocViewModel
{
public IEnumerable<CategoryModel> catModel { get; set; }
public IEnumerable<DocumentModel> docModel { get; set; }
}
So my idea is to make a recursive method in a partial view. Using Razor helpers I can make a recursive method, but I'm having a hard time with these kinds of methods.
Another problem arising is that I use IEnumerable so I have to loop through them, will that be too costly for the algorithm since I will recurse and loop again etc ...? But I also cannot make it without recursion since the depth of folders is unknown, so I have to recurse until I hit the end and then roll back up. But How?
I don't think anyone can make the algorithm but if you had some directions to point me in so I can maybe delve into recursivity and understand how to do it?
EDIT As suggested in the marked answer, here is what I would do to then build then Child lists:
public List<CategoryModel> getDocumentChilren(List<CategoryModel> categories, List<DocumentModel> documents)
{
foreach(var cat in categories)
{
if (cat.idParentCategory == 0)
continue;
foreach(var nextCat in categories)
{
if (nextCat.idParentCategory == cat.idParentCategory && nextCat.idCategory != cat.idCategory)
cat.childCategories.Add(nextCat);
}
foreach (var nextDoc in documents)
{
if (nextDoc.idCategory == cat.idCategory)
cat.childDocuments.Add(nextDoc);
}
}
return categories;
}
This is O(n^2) I believe so is it ok? If I were to make an estimation, I'd have about 20 entries per loop, so that wouldn't be too greedy?
I would organize the folders in a class more suitable for a tree structure like this:
public class CategoryModel
{
public long iDCategory { get; set; }
public string nom { get; set; }
public List<CategoryModel> ChildCategories {get;set;}
public List<DocumentModel> ChildDocuments {get;set;}
}
Then, instead of using CatDocViewModel , you could use List<CategoryModel> as the view model for the menu.

How can I model a template-like entity in DDD?

I am a beginner with DDD and I try to model elegantly in C# the next scenario:
A template that basically has only a name property on it and a list of items that have to be executed in a specific order.
public class Template
{
public string Name { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public string Name { get; set; }
public int Order { get; set; }
}
A type called Profile.
public class Profile
{
public string Name { get; set; }
}
The profile class is intended to say
I am using template A to know what items I have and in what order
If template A changes, then I am using the new version because I don't want to keep a clone of the list template A had.
If I am deleted then the template is not affected in any way
If I am created then I require a template
I can be looked after by my name only
This looks like the aggregate root would be the template, which would have a list of Items and a list of Profiles. But I feel that searching by the name of the profile is requiring me to search all the templates that have a profile with the given name. Somehow, coming from a CRUD background, it seems a high price to pay. Also, the profile is the one that uses the template and having the template know about profiles that use it, seems wrong.
How do you model this? What should be the aggregate root here? Is more than one? How do you perform the search if you want to use it from UI?
Don't. Do not start meta-modeling and over-abstracting when you need to learn DDD. It is a really bad idea, as it will focus your attention on things that have nothing to do with learning DDD, will distract you, and will lead you to making bad decisions.
You need to start with solving concrete problems. Abstractions need to come from the concrete solutions. After you have implemented (at least three of) them, it is time to look at abstractions
Neither Profile or Template can be nested within the other aggregate, they need to exist as separate aggregates. It sounds as though the Profile needs to keep a reference to which Template it is using. Therefore, I'd include a reference to the template by id (Template.Name).
public class Template
{
public string Name { get; set; }
public List<Item> Items { get; set; }
}
public class Item
{
public string Name { get; set; }
public int Order { get; set; }
}
public class Profile
{
public string Name { get; set; }
public string TemplateName { get; set; }
}

How to create MVC form from class with a List<T> property?

I am new to .NET MVC and am trying to figure out forms, I think I am on the right track but I am stuck trying to figure out how to create a form based off of a class that has an ObservableCollection<> of another class, for example:
public class Items
{
public string Notes { get; set; }
public ObservableCollection<LineItem> LineItems { get; set; }
}
and Line Items is something like:
public class LineItem
{
public string ItemNumber { get; set; }
public string QTY { get; set; }
}
From what I understand I should create an instance of Items in the controller and pass that to my view
return View(new Items());
Then on my view I use HTML helpers to create the form and when I submit the form, the model Items is sent back to the controller with filled out data. How do I go about having multiple LineItems in my view that bind to the ObservableCollection<> in my Model ? Let's say they need 2 LineItems, is there a programmatic way to show the inputs for public ObservableCollection<LineItem> LineItems multiple times, as an ObservableCollection is typically more than one instance of the class. I am using .NET MVC C# with Razor syntax.

MVC 4 - View inside a form

I'm new to MVC. I have this view model:
public class ABCView
{
public string Name { get; set; }
public List<orders> Order { get; set; }
public int Version { get; set; }
public string Message { get; set; }
}
I want a view where the top of the form will contain Name and Message. In the bottom, I need only TWO orders side-by-side. How can I achieve this for Create/Edit operations. Any links will be helpful, thanks.
I would simply pass this model to a view, then output using #Html.TextBoxFor Name and Message where you want them. On the bottom of the form have a foreach loop which goes through the List and outputs the orders.
Great, simple example:
http://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/examining-the-edit-methods-and-edit-view

Categories

Resources