I have a primary controller/view that uses an #model IEnumerable<ReportModel> for the strongly typed view. I would like to use #TextBoxFor() but this does not work with the IEnumerable (or, at least, intellisense does not like it).
Is it necessary to create a partial view or something else to allow use of the strongly typed model in creating form elements?
You need to change the IEnumerable to be an IList and loop through the records of your collection and choose the properties that will appear in the textboxes:
#model IList<ReportModel>
#for(int i = 0; i < model.Count; i++)
{
#Html.TextBoxFor(m => model[i].Property)
}
Thanks to Stephen Muecke for the correction.
Related
I have a collection of items, name it type "A", that I want to view and edit some of its attributes in a View. I would like it to save simultaneously, however, this does not seem to work as it does not seem like it is passing anything back to the Post method.
My Controller:
[HttpPost]
public ActionResult inline(IEnumerable<A> listA)
{
for (int i = 0; i <= listA.Count(); i++ )
{
A theObj = listA.ElementAt(i);
db.SaveChanges();
} //Somehow this is returning to be Null
}
My View:
#model IEnumerable<A>
#using (Html.BeginForm())
{
#Html.EditorForModel("Multiple")
}
So far this prints out all the Id of the entries (with no formatting/line breaks, of course) for some reason.
And I am not sure how to create an editor template "Multiple", this is what I have so far:
#model Models.A
#Html.EditorFor(x => x.Id)
I'm not sure where to put it / create it, so I just made it as another view in the same folder.
Any pointers how I can make this to work, so that I can edit multiple entries of the same object in the same view and pass it back to the controller and save it? I'm a newbie to MVC, so if this seems like a really simple question, I apologize in advance. Thanks!
Like most things in programming, there's multiple ways to achieve this. If you want to go the editor template route, though, it's pretty straight-forward.
As #JamieD77 pointed out, editor templates go into Views\Shared\EditorTemplates. The most important part of that path is the EditorTemplates directory convention, though. Just as with any other view in MVC, you can override/fallback depending on where you place your view. For example, Areas\Foo\Views\Shared\EditorTemplates, will work as well, but then it's only available to the Foo area. Or, you can override it for a particular controller by placing it in Views\Foo\EditorTemplates.
Then, the name of the view should correspond with the type it's intended to be used with. In your case, the view should be named A.cshtml. You can technically specify the view name manually by either passing it to EditorFor or using something like UIHint, but it's easier and more foolproof to just rely on convention here.
Inside this view, you should create the look and feel you want to have a for a single instance of A, with all editable properties represented. Then, in your main view, you simply call Html.EditorFor on the collection property, which in your case here, is the whole model:
#Html.EditorFor(model => model)
Razor will realize it has a collection and render the editor template for each item in the collection. Importantly, because it has this context, it will also be able to generate the appropriate indexes on the field names.
If you did something like the following instead:
#foreach (var item in Model)
{
#Html.EditorFor(m => item)
}
Your field names would not be indexed, and the modelbinder would not know what to do with the posted data. If you wanted to use a loop, you would have to use indexing inside the loop:
#for (var i = 0; i < Model.Count(); i++)
{
#Html.EditorFor(m => Model[i])
}
That then gives Razor the proper context to generate appropriate field names. However, importantly, that approach requires utilizing a List<T> structure, rather than something like IEnumerable<T> or ICollection<T>.
I want to create several instances of my model:
public int RestrictionID{get;set}
public string portefeuille{get;set;}
public int Min{get;set;}
public int Max{get;set;}
So I created a ViewModel that is:
public int ViewModelID{get;set;}
public ICollection<Restriction> Restrictions{get;set;}
But when using entity framework, and trying to create an instance of ViewModel(that is several instance of Restriction) nothing appears (no input for the user), same as if the compiler don't know how to represent the input of Restrictions. So what I want is exactly the same input(properties) to be filled severeal times say 4 times.
How can I achieve this? I need some help..
Thank you!
Does the ViewModelID serve any purpose? If not, you can just type your View to an IEnumerable of Restriction objects, like so:
#model IEnumerable<Restriction>
Then, in your view, you can enumerate the collection as you would any other:
#foreach (var restriction in Model)
{
#Html.DisplayFor(_ => restriction.portefeuille)
etc....
}
However worth noting that if you want to be able to edit and post back multiple instances of your model you will need to use an indexed loop like so:
#for (int i=0; i < Model.Count; i++)
{
#Html.EditorFor(_ => Model[i].portefeuille)
etc...
}
This allows the model binder to correctly bind the values.
If you do need the ViewModelId, then by all means use the ViewModel (it's good practice to use them anyway), and the same techniques still apply.
Your question is a little hard to understand, but I think your problem is merely that you have not initialized your Restrictions. For example:
model.Restrictions = new List<Restriction>
{
new Restriction(),
new Restriction(),
new Restriction(),
new Restriction()
}
Would give you four sets of Restriction fields, once you rendered this collection in your view. You might also what to do something like the following instead:
for (var i = 0; i < 4; i++)
{
model.Restrictions.Add(new Restriction);
}
That's a little less verbose, particularly if you were to have more than 4 items. Either way, the idea is that you need an actual Restriction instance in your collection for each set of fields you want rendered on the page.
If you need to add more dynamically, that's an entirely different issue that will require the use of JavaScript.
I am having trouble figuring out what is the best aproach to a rather simple problem.
I have a payment view-model that contains a list of avalible payments and some base properties like title, content...
So in my view I use #using(Html.BeginForm()) and inside that I loop over the payments and render each out and of course the view-model that I recive in my controller post has and empty list of payment methods.
I can see that if I use a for and print out model.paymentMethods[i].Prop than it can map it but is this the right aproach or can I do something even smarter?
For the model-binder to work you need to use indexed access.
#foreach (var item in Model.PaymentMethods)
{
#Html.EditorFor(m => item.Prop);
}
does NOT work.
You need to use:
#for (int i = 0; i < m.PaymentMethods.Count(), ++i)
{
#Html.EditorFor(m => m.PaymentMethods[i].Prop);
}
Otherwise the model-binder can't map it back in the post-back.
Yoy can create a editor template of Payment type. And in view you can use that editor template like:
#Html.EditorFor(m => m.PaymentMethods)
What I'm trying to do here appears to be pretty common, but I can't run this code. I get a compilation error.
I'm trying to bind to an ienumerable or icollection in a viewmodel. Is my syntax wrong? Is there a new way of doing thing I missed.
#for(var i=0; i < Model.traces.Count(); ++i)
{
#Html.EditorFor(x => x.traces[i].status)
}
The details of my architecture are at a previous post of mine that led to this...
Getting error on POST with Entity Framework - Value cannot be null. Parameter name: source
Is my syntax wrong?
Yes, IEnumerable or ICollection do not have indexer: x.traces[i].
It would be better if you used a collection whose elements can be accessed by index such as IList<T> or T[], depending on the concrete type of your view model.
Then you will be able to do this:
#model IList<MyViewModel>
...
#for (var i = 0; i < Model.traces.Count; i++)
{
#Html.EditorFor(x => x.traces[i].status)
}
The framework is quite smart in this case, if you have made your own EditorTemplate for the model Trace, you can actually just write
#Html.EditorFor(m => m.traces)
and MVC will render an editor for each item in the list and give you the right fieldnames for each index.
I'm learning MVC and I'm trying to create an implicitly typed variable for my model but not sure how to reference it in the view #model IEnumerable<???>
Controller...
public ActionResult Users() {
var model = from MembershipUser u in Membership.GetAllUsers()
select new {user = u, roles = string.Join(", ", Roles.GetRolesForUser(u.UserName))};
View(model);
}
You can't reference an anonymous-typed variable in the view (or anywhere outside its local scope). It's possible to use a dynamic type:
#model IEnumerable<dynamic>
But this way you don't have Intellisense/compile-time type checking; the best approach would be to just create a class for your model.
That's an anonymous type you're returning. I believe you'll want to use an actual type. If you don't have one for what you're selecting in your query, you'll want to create one.
Once you have your type, here's an example of using it in the view.
This is the first line in my view:
#model IEnumerable<AutoTrackerCommon.Entities.TrackerJob>
And I'm using it in a WebGrid:
#{
var grid = new #WebGrid(
source: Model,
rowsPerPage: 10);
}
You reference it as Model, but why would you do such a thing?
Use ViewModels, don't go with untyped or implicitly typed models. Its a nightmare to work with: you lose everything from IDE support to automatic validation. Don't complicate your life unnecessarily. View Models (or strongly typed views) are the way to go.
Good article to read about this: View Models in ASP.NET MVC.
Hope this is of help to you & good luck