Using #Html.TextBoxFor with ViewModel - c#

A quick question:
So, I am developing a small MVC/C# application and I am using ViewModel to pass data to my view. The ViewModel is actually a combination of 3 Models.
My Models:
public class Sourcing_ProfileSourcingAreas
{
public string Area { get; set; }
public string Details { get; set; }
}
public class DefCountry
{
public string CountryName { get; set; }
public string CountryCode { get; set; }
}
My ViewModel:
public class SourcingIndex
{
public List<DefCountry> CountryLst { get; set; }
public List<Sourcing_ProfileSourcingAreas> AreaLst { get; set; }
}
On my view, I put this line at the top #model SourcingIndex to declare that I will be using this ViewModel
I also was easily able to specify which model I want to display by using foreach loop, for example:
#foreach (Sourcing_ProfileSourcingAreas area in Model.AreaLst)
{
<tr>
<td>#area.Area</td>
<td>#area.Details</td>
</tr>
}
And
#foreach (DefCountry ctry in Model.CountryLst)
{
<option>#ctry.CountryName</option>
}
However, I am not able to create #Html.TextBox and assign it to a specific property in a model!
If possible, I want it to be somthing like this: #Html.TextBoxFor(model => model.AreaLst.Area)
Thank you

It's a bit of a weird quirk about Razor. If you try and access the objects in a foreach loop it struggles to resolve where in the model it is. You need to use this syntax:
#for (int x = 0; x < Model.CountryLst.Count(); x++)
{
#Html.TextBoxFor(t => t.CountryLst[x].CountryName)
}
this should produce an input something like
<input name="countryLst[1].CountryName"/>

#for(var i = 0; i < Model.CountryLst.Count(); i++)
{
<text>#Html.TextBoxFor(p=>Model.CountryLst[i].CountryCode)</text>
}

Related

MVC displaying collection: InvalidCastException: Unable to cast object of type 'Models.ConversionRate' to type 'System.Collections.IEnumerable'

I have an object that I am successfully passing to my view with a collection inside that is properly populated.
My Model.
conversion_rates is simply a collection of doubles:
public class Converter
{
public string result { get; set; }
public string documentation { get; set; }
public string terms_of_use { get; set; }
public string time_zone { get; set; }
public string time_last_update { get; set; }
public string time_next_update { get; set; }
public ConversionRate conversion_rates { get; set; }
}
My Controller.
currencyConverter is properly passed through to my view:
public class Rates
{
public static Converter Import()
{
try
{
string URLString = "https://v6.exchangerate-api.com/v6/APIKey/latest/gbp";
using (var webClient = new System.Net.WebClient())
{
var json = webClient.DownloadString(URLString);
Converter Test = JsonConvert.DeserializeObject<Converter>(json);
return Test;
}
}
catch (Exception e)
{
...
}
}
}
public IActionResult Index()
{
var currencyConverter = Rates.Import();
return View(currencyConverter);
}
My View:
#using System.Collections;
#model Converter
#foreach (var currency in (IEnumerable)Model.conversion_rates)
{
<tr>
<td>
#currency
</td>
</tr>
}
In the debugger, I can see that Model.conversion_rates is properly populated, but I can't get each individual element stored in my var currency for display in my table.
I can access each individual element and display them fine by just doing:
**#Successfully pulled data: #Model.conversion_rates.AED**
But for many reasons, this isn't practical. New values could be added dynamically etc. So I need to access the data in my Converter.conversion_rates, which is the collection I need to access.
This is an answer I came across, but it gives me the following error:
InvalidCastException: Unable to cast object of type 'Models.ConversionRate' to type 'System.Collections.IEnumerable'.
The most notable, similar answer I could find suggests turning my returned model itself to an IEnumerable, but it doesn't work. I'm assuming it's because I'm only returning one object, and the actual collection I want to access is inside the Converter object itself, so turning Converter into a collection of 1 doesn't help. Also if I do this, I can't access Model.conversion_rates directly either.
#model IEnumerable<Converter>
#foreach (var currency in Model.conversion_rates)
{
<tr>
<td>
#currency
</td>
</tr>
}
Appreciate any suggestions.
Edit: So an earlier fix I tried appears to be the correct one, my model is better off with:
public IEnumerable<ConversionRate> conversion_rates { get; set; }
But this messes up my json Deserialization. Will update if I find the fix.
Final code:
Just fix your class
public class Converter
{
......
public ConversionRate conversion_rates { get; set; }
public IEnumerable<ConversionRateItem> ConversionRateItems { get; set; }
}
public class ConversionRateItem
{
public string Name {get; set;}
public double Value {get; set;}
}
and action
var currencyConverter = Rates.Import();
var items = currencyConverter.conversion_rates.GetType()
.GetProperties()
.Select(p => new ConversionRateItem
{
Name=p.Name,
Value = (double) p.GetValue(currencyConverter .conversion_rates, null)
}).ToArray();
converter.ConversionRateItems=items;
converter.conversion_rates=null;
return View(currencyConverter);
and finaly view
#foreach (var currency in Model.ConversionRateItems)
{
<tr>
<td>
#currency.Name
</td>
<td>
#currency.Value
</td>
</tr>
}

Count Child Elements within a List of Parent Elements in cshtml View Model

I have a cshtml view with a model of type CategoryModel. Within the view I need to count all of the items within the model. I would like to do this as succinctly as possible, preferrably without using a for loop. Is there a better way to do this or is the below code my best option?
Models cs
public class CategoryModel
{
public string Label { get; set; }
public List<ItemGroupModel> ItemGroups { get; set; }
}
public class ItemGroupModel
{
public string Label { get; set; }
public List<ItemModel> Items { get; set; }
}
public class ItemModel
{
public string Label { get; set; }
}
Current Solution
#{
var itemGroupItemsCount = 0;
if (CategoryModel.ItemGroups.Any())
{
for (var i = 0; i < CategoryModel.ItemGroups.Count; i++)
{
if (CategoryModel.ItemGroups[i].Items.Any())
{
itemGroupItemsCount += CategoryModel.ItemGroups[i].Items.Count;
}
}
}
}
Using Linq you could do this:
var itemGroupItemsCount = CategoryModel.ItemGroups.Sum(i => i.Items.Count);
The easiest way to do this is
var count = categoryModel.ItemGroups.SelectMany(x => x.Items).Count();
The trick here is that SelectMany() flattens the resulting sequences into one sequence and project each element of the sequence.

How to get selected checkbox in a controller using model

i am trying to get the value of selected check-box using model but not able to get as i want ;
Below is the table image
below is my code for this VIEW
And below is the code for result.I get null value
And below is my model declaration
public class RoleDetail
{
[Key]
public int RoleDetailID { get; set; }
public bool IsCreate { get; set; }
public bool IsDelete { get; set; }
public bool IsView { get; set; }
public bool IsEdit { get; set; }
public bool IsDownload { get; set; }
public string ControllerName { get; set; }
public System.DateTime CreateDate { get; set; }
public Int32 UserTypeId { get; set; }
}
public enum ControllerName
{
Account, Candidate, Career, ChooseUs, ContactUs, DocumentType, Employee, Gallery, GalleryType, GetTouch, Home, JobCategory, Jobs, Portfolio, ResumeUpload, RoleDetail, Services, User, UserRoleType
}
Replace the foreach loop in your view with a for:
#for (var i = 0; i < lst.Count; i++)
{
...
#Html.CheckBoxFor(x => lst[i].IsCreate)
#Html.CheckBoxFor(x => lst[i].IsView)
#Html.CheckBoxFor(x => lst[i].IsDelete)
...
}
For this to work make sure that the variable you are iterating over is an IList<T> or T[].
Also your controller action argument should be named accordingly:
public ActionResult Create(IEnumerable<RoleDetail> lst)
{
...
}
You should not be creating RoleDetail in the view. In the GET method create a List<RoleDetail>, populate it with the objects you want to display and return it to the view.
Controller
public ActionResult Create()
{
List<RoleDetail> model = new List<RoleDetail>();
// populate the collection, for example
foreach(var name in Enum.GetNames(typeof(ControllerName)))
{
model.Add(new RoleDetail()
{
ControllerName = name,
IsCreate = true // etc
});
}
return View(model);
}
public ActionResult Create(IEnumerable<RoleDetail> model)
{
}
View
#model List<RoleDetail>
#using(Html.BeginForm())
{
for(int i = 0; i < Model.Count; i++)
{
#Html.HiddenFor(m => m.ControllerName) // needed for postback
#Html.DisplayFor( => m.ControllerName)
#Html.CheckBoxFor(m => m.IsCreate)
....
}
<input type="submit" />
}
Side notes
Do not try to override the name (or value) attribute. The html
helper set these correctly for model binding (and in any case you
were only setting it to the value the helper generated anyway)
The reason the foreach loop does not work is your generating
duplicate name attributes (and also invalid html due to duplcate
id attributes). The for loop correctly generates the correct
names with indexers (e.g. <input name="[0].IsCreate " ..>, <input
name="[1].IsCreate " ..> etc.
You don't appear to be rendering controls for all of you model
properties so use a view model containing only those properties you
need to display/edit. What is a view model in MVC
You have public enum ControllerName so I suspect property
ControllerName in RoleDetail should be public ControllerName ControllerName { get; set; }?
And in future, post the code, not an image of it!

MVC3 View Model - List of Complex Objects, containing Lists

How do I bind such a complex model with multiple layers that contain multiple objects?
Right now I pass the model to the view - (populating a form / a check box tree) and I would like the exact model back (SubjectSelectionModel) but it's not binding correctly.
Could anyone elaborate on the process I need to take in order to bind these correctly in my view?
View Model:
public class SubjectSelectionModel
{
public IList<Subject> Subjects { get; set; }
}
Subject Class:
public class Subject
{
public String Name { get; set; }
public IList<Bin> Bins { get; set; }
public Subject()
{
}
public Subject(IList<Course> courses)
{
}
}
Bin Class:
public class Bin
{
public Subject Subject { get; set; }
public int Amount { get; set; }
public IList<Foo> Foos { get; set; }
}
Foo Class:
public class Foo
{
public int Number { get; set; }
}
This is where Editor Templates come in handy. Rather than messing around with this, you can use simple editor templates to handle all the grunt work for you.
You would create several templates in ~/Views/Shared/EditorTemplates, and then in your primary view it should look like this:
View.cshtml
#model SubjectSelectionModel
#using(Html.BeginForm()) {
#EditorFor(m => m.Subjects)
<input type="submit" />
}
Subject.cshtml
#model Subject
#Html.EditorFor(m => m.Name)
#Html.EditorFor(m => m.Bins)
Bin.cshtml (I assume you don't want to render Subject, this would be an infinite loop)
#model Bin
#Html.EditorFor(m => m.Amount)
#Html.EditorFor(m => m.Foos)
Foo.cshtml
#model Foo
#Html.EditorFor(m => m.Number)
Obviously, you may want to change the html formatting to whatever you want, but that's essentially it.
You need a for loop for the objects so MVC can bind using the index in the collection.
Example:
for (int subjectIndex = 0; subjectIndex < Model.Subjects.Count; subjectIndex++) {
#Html.TextBoxFor(x => x.Subjects[subjectIndex].Name)
for (int binIndex = 0; binIndex < Model.Subjects.Bins.Count; binIndex++) {
#Html.TextBoxFor(x => x.Subjects[subjectIndex].Bins[binIndex].Amount)
}
}
..etc.
I gave a similar response to a similar question, here: Generating an MVC RadioButton list in a loop

Translate SQL to LINQ and how display new results into the view?

I have to questions:
1) How to translate this select to LINQ?
Select i.ID, i.Impression,
(Select COUNT(ImpressionsId)
from DiaryImpressions
where DiaryPostsId = '2' AND ImpressionsId = i.ID) as Num from Impressions i
2) I have to run this query inside a loop where I could replace the hard coded value 2 for the real post ID. But how could I do this in C# with MVC3? Could someone give me any example on how it works inside foreach loop and how could I display this value in the view?
Thanx a lot =)
Have you already got a database context/repository set up to communicate with the database in your MVC project? Below I'm assuming you've got a database context named dbContext.
Note: If you're not using Razor, replace the "#" with "<%" and close with "%>"
You can either put the item in the ViewBag, or in the Model (I prefer Model) like below. I'm not sure what you want to do with these counts, so i've put them in a list. You'll need a class to put your impression info in, i've added it below;
Model Code:
public class MyModel
{
public class ImpressionInfo //just used to store your results sub class of the model
{
public ImpressionInfo(id, impression, diaryImpressionCount)
{
Id = id;
Impression = impression;
DiaryImpressionCount = diaryImpressionCount
}
public int Id { get; set; }
public int Impression { get; set; } //is this an int? you didn't say
public int DiaryImpressionCount { get; set; }
}
public MyModel()
{
var impressionInfo = new List<ImpressionInfo>()
foreach (var di in dbContext.DiaryImpressions)
{
ImpressionInfos.Add(new ImpressionInfo(
di.Id,
di.Impression,
dbContext.DiaryPosts
.Count(dp => dp.ImpressionsId == di.ID));
}
}
public List<ImpressionInfo> ImpressionInfos { get; set; }
then in the view
View Code:
#model MyModel
#if(Model.ImpressionInfos.Count > 0)
{
<table>
<tr>
<td>Impression</td>
<td>Count</td>
</tr>
foreach (var i in Model.ImpressionInfos)
{
<tr>
<td>#i.Impression</td>
<td>#i.DiaryImpressionCount</td>
</tr>
}
}
else
{
<p>No Impression infos</p>
}
Hope this helps.

Categories