So im working with this complex anonymous object
var result = new
{
percentage = "hide",
bullets = (string)null,
item = new [] {
new {
value = 16,
text = "Day",
prefix = (string)null,
label = (string)null
},
new {
value = 41,
text = "Week",
prefix = (string)null,
label = (string)null
},
new {
value = 366,
text = "Month",
prefix = (string)null,
label = (string)null
}
}
};
And I want to convert it into a ViewModel and return it as JSON from a rest API.
What I would like to know is
How do I represent this as a model including the array item entries
How do I then add array items to the array once an instance of the model is created
Does the model need a constructor to initialize the array.
Any help or examples you could provide would be great.
Create a class with the structure:
public class Result
{
public Result()
{
// initialize collection
Items = new List<Item>();
}
public string Percentage { get; set; }
public string Bullets { get; set; }
public IList<Item> Items { get; set; }
}
public class Item
{
public int Value { get; set; }
public string Text { get; set; }
public string Prefix { get; set; }
public string Label { get; set; }
}
Then change your code to this:
var result = new Result
{
Percentage = "hide",
Bullets = (string)null,
Items = {
new Item {
Value = 16,
Text = "Day",
Prefix = (string)null,
Label = (string)null
},
new Item {
Value = 41,
Text = "Week",
Prefix = (string)null,
Label = (string)null
},
new Item {
Value = 366,
Text = "Month",
Prefix = (string)null,
Label = (string)null
}
}
};
Addressed above with the structure.
Add to collection as follows:
result.Items.Add(new Item {
Value = 367,
Text = "Month",
Prefix = (string)null,
Label = (string)null
});
I would initialize the collection in the constructor as above.
To return the json from your controller action add the following:
return Json(result, JsonRequestBehavior.AllowGet);
Related
I'm trying to figure out how I can add an object list property to an existing object, which also has a list object property. I have 3 classes as FirstList, SecondList, and ThirdList with an Id and Text Property. ThirdList has a List Property of SecondList and SecondList has a List Property of FirstList. I've tried nesting .Add() but I can't get that to work.
//Classes
public class FirstList
{
public int Id { get; set; }
public string Text { get; set; }
}
public class SecondList
{
public int Id { get; set; }
public string Text { get; set; }
public List<FirstList> Firsts { get; set; } = new List<FirstList>();
}
public class ThirdList
{
public int Id { get; set; }
public string Text { get; set; }
public List<SecondList> Seconds { get; set; } = new List<SecondList>();
}
// program
ThirdList item = new ThirdList();
item.Id = 30;
item.Text = "Third Text";
item.Seconds.Add(new SecondList
{
Id = 20,
Text = "Second Text",
Firsts.Add(new FirstList //Trying to add a list object within the .Add method
{
Id = 10,
Text = "First Text"
})
});
// If I remove the 'Firsts' property from 'Seconds'.Add method and do the following below, I can
// add it afterwords. But, I was trying to see if it all could be added at once.
// item.Seconds[0].Firsts.Add(new FirstList
// {
// Id = 10,
// Text = "First Text"
// });
List<T>.Add(T) method is used to add an object to the end of the List<T>. You have to instantiate the List<T> first before you use the .Add(T) method.
If I am not mistaken, what you are asking is how to initialize a list of objects. Take a look on below codes, notice the bracket { }.
ThirdList item = new ThirdList()
{
Id = 30,
Text = "Third Text",
Seconds =
{
new SecondList
{
Id = 20,
Text = "Second Text",
Firsts =
{
new FirstList
{
Id = 10,
Text = "First Text"
}
}
}
}
};
I am trying to create the json from c# object which holds the data.
Data is in simple table format. Consist of Columns: Name, InputCode, DisplayID, CodeID, ParentID.
If Parent(Net) then ParentID is null. If Children(Subnet), has ParentID that holds CodeID of Parent(Net).
CodeID is Unique.
I am facing the issue with iternation under subnet using foreach. It dosen't allow.
public class CodeFrameJson
{
public string Name { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public int? InputCodeValue { get; set; }
public int DisplayId { get; set; }
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public List<CodeFrameJson> Subnet { get; set; }
}
List<CodeFrameJson> cfj = new List<CodeFrameJson>();
IEnumerable<CodeDTO> _cfd = new List<CodeDTO>();
_cfd = codeFrameJson.GetCodeFrame(questionId, projectName);
_cfd = _cfd.OrderBy(a => a.DisplayOrderNo).ToList();
foreach (var a in _cfd)
{
int CodesID = 0;
CodeFrameJson obj = new CodeFrameJson();
if (a.InputCodeValue == null)
{
var root = new CodeFrameJson()
{
Name = a.CodeName,
DisplayId = a.DisplayOrderNo,
InputCodeValue = null,
Subnet = new List<CodeFrameJson>()
{
//Start: Not allowing foreach
foreach (var x in _cfd)
{
if (x.ParentId == CodesID)
{
new CodeFrameJson()
{
Name = x.CodeName,
InputCodeValue = x.InputCodeValue,
DisplayId = x.DisplayOrderNo
};
}
}
//End: Not allowing foreach
}
};
obj = root;
}
else {
var root = new CodeFrameJson()
{
Name = a.CodeName,
DisplayId = a.DisplayOrderNo,
InputCodeValue = a.InputCodeValue,
Subnet = null
};
obj = root;
}
cfj.Add(obj);
}
var json = JsonConvert.SerializeObject(cfj, Formatting.Indented);
Final Output Something like this which can be distinguished easily
{
"Site": {
"Name": "Site",
"DisplayID": 1,
"Subnet": [
{
"Name": "Full Site",
"InputCodeValue": 1,
"DisplayId": 2
},
{
"Name": "Partial Site",
"InputCodeValue": 2,
"DisplayId": 3
}
]
},
"Test": {
"Name": "Test1",
"InputCodeValue": 3,
"DisplayId": 4
}
}
This doesn't really have to do anything with JSON, but with object (collection) initialization. You can only assign values there, but LinQ comes to the rescue:
Simply filter your list and create the new objects in the select statement:
Subnet = _cfd.Where(x => x.ParentId == CodesID).Select(x => new CodeFrameJson
{
Name = x.CodeName,
InputCodeValue = x.InputCodeValue,
DisplayId = x.DisplayOrderNo
}).ToList()
I have the following code which returns results from a database table comprising of an Id field and a Name field, and transfers it to a list of SelectListItems (this populates a dropdown box in my view.)
var locationTypes = await APIHelper.GetAsync<List<LocationType>>(url);
var items = new List<SelectListItem>();
items.AddRange(locationTypes.Select(locationType =>
{
var item = new SelectListItem();
item.Value = locationType.LocationTypeId.ToString();
item.Text = locationType.Name;
return item;
}));
I am repeating this a lot throughout my application, substituting LocationType for various other things. The item.Value always gets the Id property of the data returned (the Id field is always in the format of {TableName}+"Id"), and the item.Text always gets ".Name" property.
How can I make this generic? I am trying to achieve something like this, although it is syntactically incorrect and may be the incorrect approach:
var myGenericObjects = await APIHelper.GetAsync<List<T>>(url)
var items = new List<SelectListItem>();
items.AddRange(myGenericObjects .Select(myGenericObjects =>
{
var item = new SelectListItem();
item.Value = myGenericObject.Field[0].ToString();
item.Text = myGenericObject.Name;
return item;
}));
You can create a custom extension for a generic list object, then, using reflection retrieve the values that you are wanting to map to the SelectListItem.Text and Name fields. Note I am using "nameof" in order to prevent any confusion or magic string representations of the properties to which I am trying to map.
I did define a default value of "Name" to the namePropertyName parameter. Per your description it sounded like, by convention, most of your DTOs have the property "Name" in them. If that's not the case simply remove the default value that is defined.
There are additional checks that could be made to this extension to prevent NullReference and ArgumentExceptions as well, but for simplicity of the example were left out. Example: Ensuring a value is provided in the idPropertyName and namePropertyName parameters and ensuring those property names exist on the provided generic object prior to conversion.
public static class ListExtensions
{
public static List<SelectListItem> ToSelectList<T>(this List<T> list, string idPropertyName, string namePropertyName = "Name")
where T : class, new()
{
List<SelectListItem> selectListItems = new List<SelectListItem>();
list.ForEach(item =>
{
selectListItems.Add(new SelectListItem
{
Text = item.GetType().GetProperty(namePropertyName).GetValue(item).ToString(),
Value = item.GetType().GetProperty(idPropertyName).GetValue(item).ToString()
});
});
return selectListItems;
}
}
Example Use:
var testList = new List<TestDto>
{
new TestDto { Name = "Test0", TestId = 0 },
new TestDto { Name = "Test1", TestId = 1 },
new TestDto { Name = "Test2", TestId = 2 },
new TestDto { Name = "Test3", TestId = 3 },
new TestDto { Name = "Test4", TestId = 4 },
};
var selectList = testList.ToSelectList(nameof(TestDto.TestId), nameof(TestDto.Name));
Here is the TestDto class for reference:
public class TestDto
{
public int TestId { get; set; }
public string Name { get; set; }
}
Some Prep Work
If you can change the table column names, then use a convention. For example, always name the "Value" column "X", and the "Text" column "Y" (give them better names). Then make all the classes for those tables implement an interface similar to this:
public interface ICustomLookup
{
string X { get; set; }
string Y { get; set; }
}
public class SomeClass : ICustomLookup
{
public string X { get; set; }
public string Y { get; set; }
}
Then an extension method like so:
public static class EnumerableExtension
{
public static SelectList ToSelectList(this IEnumerable<ICustomLookup> items)
{
return new SelectList(items.Select(thisItem => new SelectListItem
{
Text = thisItem.X,
Value = thisItem.Y
}));
}
}
Usage
var items = new List<SomeClass>
{
new SomeClass { X = "XOne", Y = "YOne" },
new SomeClass { X = "XTwo", Y = "YTwo" }
};
SelectList selectList = items.ToSelectList();
I am trying to create a dynamic control based in MVC,
I got a solution to implement.. it working fine..
with this code
public class DynamicControlViewModel
{
public ControlViewModel[] Controls { get; set; }
}
public abstract class ControlViewModel
{
public abstract string Type { get; }
public bool Visible { get; set; }
public string Label { get; set; }
public string Name { get; set; }
}
public class TextBoxViewModel : ControlViewModel
{
public override string Type
{
get { return "textbox"; }
}
public string Value { get; set; }
}
public class CheckBoxViewModel : ControlViewModel
{
public override string Type
{
get { return "checkbox"; }
}
public bool Value { get; set; }
}
public class DropDownListViewModel : TextBoxViewModel
{
public override string Type
{
get { return "ddl"; }
}
public SelectList Values { get; set; }
}
This is the way i am calling the object
public ActionResult Index()
{
return View(GetControls1());
}
public DynamicControlViewModel GetControls1()
{
var model1 = new DynamicControlViewModel
{
Controls = new ControlViewModel[] {
new DropDownListViewModel{Visible = true,Label = "drop label",Name = "DropDown1",Values = new SelectList(new[]{new { Value = "1", Text = "text 1" },new { Value = "2", Text = "text 2" },new { Value = "3", Text = "text 3" },}, "Value", "Text", "2")},
new TextBoxViewModel { Visible = true, Label = "label 1", Name = "TextBox1", Value = "value of textbox" },
new CheckBoxViewModel { Visible = true, Label = "CheckBox label 1", Name = "CheckBox1", Value = true},
new TextBoxViewModel { Visible = true, Label = "label 2", Name = "TextBox2", Value = "value of textbox" }}
};
return model1;
}
Here,
I need to use for loop to create the dynamic control..
here is my code, getting error
public DynamicControlViewModel GetControls()
{
var model = new DynamicControlViewModel { };
var Controls1 = new ControlViewModel[] { };
var s = model.Controls;
//int i=0;
//for loop start
Controls1[0] = new TextBoxViewModel { Visible = true, Label = "label 2", Name = "TextBox2", Value = "value of textbox" };
Controls1[1] = new TextBoxViewModel { Visible = true, Label = "label 3", Name = "TextBox3", Value = "value of textbox" };
Controls1[2] = new CheckBoxViewModel { Visible = true, Label = "CheckBox label 1", Name = "CheckBox1", Value = true },
Controls1[3] = new DropDownListViewModel { Visible = true, Label = "drop label", Name = "DropDown1", Values = new SelectList(new[] { new { Value = "1", Text = "text 1" }, new { Value = "2", Text = "text 2" }, new { Value = "3", Text = "text 3" }, }, "Value", "Text", "2") },
//loop end
var model1 = new DynamicControlViewModel
{
Controls = Controls1
};
return model1;
}
The problem is that you first define an array of size 0 (i.e. with 0 cells to hold values):
var Controls1 = new ControlViewModel[] { }; // array with length 0
Afterwards you try to assign to the first, second, third and fourth cell of the array, which do not exist. Therefore you get the error.
So you should either use a List<ControlViewModel> or initialize an array of the correct length:
var Controls1 = new ControlViewModel[4];
I'm trying to do this:
This is my ViewModel and Model:
public class OpeningYearViewModel
{
public int OpeningYearId { get; set; }
public string Description { get; set; }
public List<Grade> GradesList { get; set; }
}
public class Grade
{
public int GradeId { get; set; }
public string Name { get; set; }
public int CurrencyId { get; set; }
public int Cost { get; set; }
}
This is my Controller. I build a SelecList here and pass it to the view through the ViewBag
OpeningYearViewModel viewmodel = new OpeningYearViewModel {
OpeningYearId = 1,
Description = "2015 - II",
GradesList = new List<Grade>
{
new Grade { GradeId = 1, Name = "Grade 1", CurrencyId = 1, Cost = 100 },
new Grade { GradeId = 2, Name = "Grade 2", CurrencyId = 2, Cost = 200 },
new Grade { GradeId = 3, Name = "Grade 3", CurrencyId = 2, Cost = 150 }
}
};
SelectList list = new SelectList(
new List<SelectListItem>
{
new SelectListItem { Text = "S/.", Value = "1"},
new SelectListItem { Text = "$", Value = "2"},
}, "Value" , "Text");
ViewBag.currencyList = list;
return View(viewmodel);
And in my View I need a DropDownListFor for every item on GradesList so I do this:
#model Test.Models.OpeningYearViewModel
#for(int i = 0; i < Model.GradesList.Count; i++)
{
#Html.DropDownListFor(x => x.GradesList[i].CurrencyId, new SelectList(ViewBag.currencyList, "Value", "Text"))
#Model.GradesList[i].CurrencyId //This is just to know the CurrencyId on every item.
}
I'm getting every select correctly rendered, but I can't get the correct option selected on the page load:
render of view
It is possible to do what I'm trying to do and I'm doing something wrong, or DropDownListFor works in a different way?
Thanks!
I can't understand why this is happening but you can workaround it by setting explicitly the selected value. This can be done by passing Model.GradesList[i].CurrencyId as fourth parameter to the SelectList's constructor:
#for(int i = 0; i < Model.GradesList.Count; i++)
{
#Html.DropDownListFor(x => x.GradesList[i].CurrencyId,
new SelectList(ViewBag.currencyList, "Value", "Text", Model.GradesList[i].CurrencyId))
}
Since, the DropDownListFor is used in loop to generate indexed inputs; so generate input controls will be generated with name as "GradeList[0].CurrencyId", "GradeList[1].CurrencyId"......Due to this framework will not bind the selected value in Select List as it is unable to get the value in reflection for selection. That's why you have to use the following SelectList constructor to set the selected value.
public SelectList(
IEnumerable items,
string dataValueField,
string dataTextField,
object selectedValue
)
However, if your DropDownListFor is bind to a simple expression like
#Html.DropDownListFor(model => model.CurrencyId, new SelectList(ViewBag.Items, "Value", "Text"))
then selection will work automatically.