How to set Id for EditorFor() html helper in asp .net MVC3 - asp.net-mvc-3

I used this to override framework generated id #Html.EditorFor(model => model.cost, new { id = "checkCost" })But unfortunately id is not changing. i.e When i use string d = Request.Form["checkCost"];
at controller action then string filled with null value.WHY?? I also replaced EditorFor with TextBoxFor but nothing changed then also controller takes cost as ID
<td >
#Html.DropDownList("check_master", "--select package--")
</td>
<td >
#Html.EditorFor(model => model.check_name)
#Html.ValidationMessageFor(model => model.check_name)
</td>
<td >
#Html.EditorFor(model => model.cost, new { id ="checkCost" })
#Html.ValidationMessageFor(model => model.cost)
</td>
Updated:
This is my partial view and my main view(rendering partial from ajax.actionLink) also hold a EditorFor(model=>mode.cost)
Partial view is strongly typed to Check_master table and main view is strongly typed to package_master where both entitySet hold same name property i.e "COST" Secondly both partial and main view hold EditorFor "cost"I tried to change the name of check_master property like by
[Column("check_cost")]
public Nullable cost { get; set; }But dont know why this is not working i.e property naem is not changing while referring it like
model.something

Create 2 view models with properties CheckCost and PackageCost that way there's a seperation:
public class CheckViewModel{
public string CheckCost{get;set;}
}
public class PackageViewModel{
public string PackageCost{get;set;}
}
This way avoid conflicts.

To specifically answer the question asked, try this:
#Html.EditorFor(model => model.cost, new { #id = "checkCost" })
Note the slight (but important) difference: ... new { #id = "checkCost" })

Related

MVC 5 Conditional Validation Option?

I'm developing an MVC 5 web application. Within a particular View I need to validate a ViewModel, however, I need some of the validation only to occur depending on the users inpupt.
For example, I have a ViewModel
public class TimeEntryViewModel
{
public int proposalID { get; set; }
public int proposalCode { get; set; }
public int nonchargeCode { get; set; }
public SelectList UserProposals { get; set; }
public SelectList TimeEntryClientCodes { get; set; }
public SelectList TimeEntryNonChargeCodes { get; set; }
}
This ViewModel is passed to a View which looks like this
<div class="form-group">
#Html.LabelFor(m => m.proposalID, "Proposal")
#Html.DropDownListFor(m => m.proposalID, Model.UserProposals, "No Proposal", new { #class = "form-control"})
#Html.ValidationMessageFor(m => m.proposalID)
</div>
<div id="ClientCodes" class="form-group" style="display:none">
#Html.LabelFor(m => m.proposalCode, "Client")
#Html.DropDownListFor(m => m.proposalCode, Model.TimeEntryClientCodes, "Select", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.proposalCode)
</div>
<div id="NonChargeCodes" class="form-group">
#Html.LabelFor(m => m.nonchargeCode, "Non Charge")
#Html.DropDownListFor(m => m.nonchargeCode, Model.TimeEntryNonChargeCodes, "Select", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.nonchargeCode)
</div>
If the user selects 'No Proposal' from the first drop down list, then the drop down list 'nonchargeCode' appears and I need to validate so that the user selects an option from it.
However, if the user selects another option from the first down drop list, then the drop down list 'nonchargeCode' will disappear and another drop down called 'proposalCode' will appear. I then want to validate to ensure the user selects an option from this drop down, but not the 'nonchargeCode' (which will be hidden).
In an MVC 4 application I previously coded, I used http://fluentvalidation.codeplex.com/ to help with this scenario.
I'm just wondering if anyone else had used anything else to overcome this problem of conditional validation? If so, I'd be keen to hear.
Thanks again.
You can use conditional validation in jQuery and in fluentvalidation.
You can use a jQuery selector on the validation, something like this.
I'm not sure about the HTML element names.
$( "#myform" ).validate({ rules: {
proposalCode: {
required: "#proposalCode:visible"
} }
Check out jQuery Dependency expression for more information.
In FluentValidation validation (Server side only) you can use the 'When' expression.
RuleFor(r => r.proposalCode).NotNull().When(e => // Check selected value);
Check out the documentation here
I think this should get you started.

MVC3 - Viewmodel with list of complex types

Apologies if this has been asked before; there are a million ways to phrase it so searching for an answer has proved difficult.
I have a viewmodel with the following properties:
public class AssignSoftwareLicenseViewModel
{
public int LicenseId { get; set; }
public ICollection<SelectableDeviceViewModel> Devices { get; set; }
}
A simplified version of SelectableDeviceViewModel would be this:
public class SelectableDeviceViewModel
{
public int DeviceInstanceId { get; set; }
public bool IsSelected { get; set; }
public string Name { get; set; }
}
In my View, I am attempting to display a list of editable checkboxes for the Devices property, inside an input form.
Currently, my View looks like this:
#using (Html.BeginForm())
{
#Html.HiddenFor(x => Model.LicenseId)
<table>
<tr>
<th>Name</th>
<th></th>
</tr>
#foreach (SelectableDeviceViewModel device in Model.Devices)
{
#Html.HiddenFor(x => device.DeviceInstanceId)
<tr>
<td>#Html.CheckBoxFor(x => device.IsSelected)</td>
<td>#device.Name</td>
</tr>
}
</table>
<input type="submit" value="Assign" />
}
The problem is, when the model gets posted back to the controller, Devices is null.
My assumption is that this is happening because even though I'm editing its contents, the Devices property is never explicitly included in the form. I tried including it with HiddenFor, but that just resulted in the model having an empty list instead of null.
Any idea what I'm doing wrong here?
My assumption is that this is happening because even though I'm
editing its contents, the Devices property is never explicitly
included in the form.
No, your assumption is wrong. The reason this doesn't get bound properly is because your input fields doesn't have correct names. For example they are called name="IsSelected" instead of name="Devices[0].IsSelected". Take a look at the correct wire format that needs to be used to bind to collections: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx
But why this happens?
It happens because of the foreach loop that you used in your view. You used x => device.IsSelected as lambda expression for the checkbox but this doesn't take into account the Devices property at all (as you can see by looking at the generated source code of your web page).
So what should I do?
Personally I would recommend you using editor templates as they respect the navigational context of complex properties and generate correct input names. So get rid of the entire foreach loop in your view and replace it with a single line of code:
#Html.EditorFor(x => x.Devices)
and now define a custom editor template that will automatically be rendered by ASP.NET MVC for each element of the Devices collection. Warning: the location and name of this template are very important as this works by convention: ~/Views/Shared/EditorTemplates/SelectableDeviceViewModel.cshtml:
#model SelectableDeviceViewModel
#Html.HiddenFor(x => x.DeviceInstanceId)
<tr>
<td>#Html.CheckBoxFor(x => x.IsSelected)</td>
<td>#Html.DisplayFor(x => x.Name)</td>
</tr>
Another approach (which I don't recommend) is to change your current ICollection in your view model to an indexed collection (such as an IList<T> or an array T[]):
public class AssignSoftwareLicenseViewModel
{
public int LicenseId { get; set; }
public IList<SelectableDeviceViewModel> Devices { get; set; }
}
and then instead of the foreach use a for loop:
#for (var i = 0; i < Model.Devices.Count; i++)
{
#Html.HiddenFor(x => x.Devices[i].DeviceInstanceId)
<tr>
<td>#Html.CheckBoxFor(x => x.Devices[i].IsSelected)</td>
<td>#Html.DisplayFor(x => x.Devices[i].Name</td>
</tr>
}
EditorFor templates work and keep the code clean. You don't need the loops and the model is posted back correctly.
However, has anyone had problems with validation on complex viewmodels (nested EditorFor templates)? I'm using Kendo Validator and am running into all sorts of jquery errors.

MVC3 collection model binding with EditorFor

Regarding this post and this other one.
Suppose I have the following:
public class Foo
{
public string Value1 { get; set; }
public string Value2 { get; set; }
}
public class BarViewModel
{
public string Baz { get; set; }
public IList<Foo> Foos { get; set; }
}
And I have a view that receive a BarViewModel:
#model BarViewModel
#Html.EditorFor(model => model.Baz)
<table>
#for(int i = 0 ; i < Model.Foos.Count ; i ++)
{
string name1 = "Foos[" + i.ToString() + "].Value1";
string name2 = "Foos[" + i.ToString() + "].Value2";
<tr>
<td>
<input type="text" name="#name1" value="#Model.Foos[i].Value1" />
</td>
<td>
<input type="text" name="#name2" value="#Model.Foos[i].Value2" />
</td>
</tr>
}
</table>
And in my controller I have a POST method that recive the BarViewModel.
Given the inputs names generated for Value1 and Value2 are "Foos[0].Value1" and "Foos[1].Value1" and so on, the collection on the BarViewModel, in the POST method, is automatically filled by the ModelBinder. Awesome.
The problem is, if I do it this way in my view :
#for(int i = 0 ; i < Model.Foos.Count ; i ++)
{
<tr>
<td>
#Html.EditorFor(model => model.Foos[i].Value1);
</td>
<td>
#Html.EditorFor(model => model.Foos[i].Value2);
</td>
</tr>
}
Then the names generated for the input are like "Foos__0__Value1", and that break the model binding. The Foos property of my BarViewModel, in my POST method, is now null
I am missing something?
Edit
If I use EditorFor on the collection itself:
#EditorFor(model => model.Foos)
The names are generated correctly. But that force me to build a ViewModel in /Views/Share to handle the type Foos, that will generate the row, wich I dont really want to do...
Edit 2
I will clarify my question here, I understand that it's a bit vague.
If I do :
#EditorFor(model => model.Foos)
The names of the inputs will have the form "Foos[0].Value1" and the model binding works just fine on posts.
But if I do :
#for(int i = 0 ; i < Model.Foos.Count ; i ++)
{
#EditorFor(model => Model.Foos[0].Value1)
}
The names takes the form "Foos__0__Value1" and the model binding does not works. On my post method, model.Foos will be null.
Is there a reason why the second syntax breaks the model binding?
I'm not entirely sure just exactly what your question is. However, this is how MVC works. EditorFor uses EditorTemplates, and you define an editor template for your type. It doesn't have to go in Share, it can go in whatever level you're using. For instance, you can have it at /Views/Home/EditorTemplates/Foos.cshtml, so long as you aren't using it anywhere other than your Home controller.

How can I retrieve the List in my controller?

My controller always gets "null" for the "adjModel" parameter.
How can I retrieve the values?
CONTROLLER
[HttpPost]
public ActionResult AdjustmentList(List<AdjustmentVM> adjModel)
{
// adjModel is null
}
VIEW
#model List<ExtFramework.ViewModels.BillingArea.AdjustmentVM>
<div class="no-fancybox">
#using (Html.BeginForm("AdjustmentList", "Deposit", new { depositId = ViewBag.depositId }))
{
<div>
<table id="adjustment">
<tr>
<th>Description</th>
<th>Montant</th>
</tr>
#foreach(var item in Model)
{
<tr>
<td>#Html.TextBoxFor(model => item.Description)</td>
<td>#Html.TextBoxFor(model => item.Amount)</td>
</tr>
}
</table>
<input type="submit" value="" class="save" />
</div>
}
</div>
MODEL
namespace ExtFramework.ViewModels.BillingArea
{
public class AdjustmentVM
{
public int AdjustmentId { get; set; }
public string Description { get; set; }
public decimal Amount { get; set; }
public int DepositId { get; set; }
}
}
This is where editor templates are useful. Instead of using a foreach loop to go through the list of view models, use #Html.EditorFor(m => m). Then, in a subfolder named EditorTemplates (an MVC naming convention) add a view with the name AdjustmentVM.cshtml. Again, this is another MVC naming convetion - using the name of the type being used. This file would look like:
#model AdjustmentVM
<tr>
<td>#Html.TextBoxFor(model => model.Description)</td>
<td>#Html.TextBoxFor(model => model.Amount)</td>
</tr>
The runtime will automatically loop over the items in the list and render the contents of the editor template, giving unique names for each form value, so that the default model binder can map these to the properties on the view model on postback.
You can customise the name of the editor template if you want, look a the UIHintAttribute class.
By default, when you want a collection, you need to make sure the names of the controls indicate they are from an array, etc. The default binder doesn't have this magic to my knowledge.

When do I use View Models, Partials, Templates and handle child bindings with MVC 3

new to mvc3, i have a few questions, would appreciate if someone could answer/provide links:
When should I use View Models? Is it not recommended to use the domain? I find that my view models are copies of my domain objects, and don't see the value...
When should I use Partials? Is it only if the partial view will be reused?
When should I use Display Templates and Editor Templates? Can I use these without a view model?
How do I create an edit screen where the parent and list of child objects are both editable? i.e. a few fields at the top (parent) and a grid of fields below (like editable rows), particularly, how do i do the binding? automapper is not used.
Thanks!
When should I use View Models? Is it not recommended to use the domain? I find that my view models are copies of my domain objects, and don't see the value...
View models should always be used. You should not use your domain models in the view.
View models are not exact copies of the domain models. They always have some differences related to the specific requirements of the view. For example on one screen you would like to present some of the properties of your domain model and on other screen other properties. As a consequence to this you will also have different validation requirements as one property will be required on one screen and not required on other screen. So you will also have different data annotations on those view models.
When should I use Partials? Is it only if the partial view will be reused?
Not only if the view will be reused. Partials could be used to make your views more structured. Also if you are using AJAX, partials make it easier. You would send the AJAX request to a controller action which will return a partial view allowing you to update only portions of the DOM.
When should I use Display Templates and Editor Templates? Can I use these without a view model?
Always. You can use them with any strongly typed model, but you should always use a view models (see answer to previous question).
How do I create an edit screen where the parent and list of child objects are both editable? i.e. a few fields at the top (parent) and a grid of fields below (like editable rows), particularly, how do i do the binding? automapper is not used.
That's a pretty broad question but to answer it as always you start with defining your view models which will represent/contain the properties you would like to present on this screen for editing:
public class ChildViewModel
{
[Required]
public string Name { get; set; }
}
public class ParentViewModel
{
[Required]
public string Name { get; set; }
public IEnumerable<ChildViewModel> Children { get; set; }
}
then a controller:
public class HomeController: Controller
{
public ActionResult Index()
{
// TODO: Fetch an actual domain model from your repository,
// and map it to the view model (AutoMapper is a great tool for the job)
var model = new ParentViewModel
{
Name = "parent name",
Children = Enumerable.Range(1, 5).Select(x => new ChildViewModel
{
Name = "child " + x
})
};
return View(model);
}
[HttpPost]
public ActionResult Index(ParentViewModel model)
{
if (!ModelState.IsValid)
{
return View(model);
}
// TODO: the model object here will contain the new values
// => user AutoMapper to map it back to a domain model
// and pass this domain model to the repository for processing
return RedirectToAction("Index");
}
}
and finally the view:
#model ParentViewModel
#using (Html.BeginForm())
{
<h2>Parent</h2>
<div>
#Html.LabelFor(x => x.Name)
#Html.EditorFor(x => x.Name)
#Html.ValidationMessageFor(x => x.Name)
</div>
<h2>Children</h2>
<table>
<thead>
<tr>
<th>Child name</th>
</tr>
</thead>
<tbody>
#Html.EditorFor(x => x.Children)
</tbody>
</table>
<input type="submit" value="OK" />
}
and the last piece is the editor template for a child (~/Views/Home/EditorTemplates/ChildViewModel.cshtml):
#model ChildViewModel
<tr>
<td>
#Html.LabelFor(x => x.Name)
#Html.EditorFor(x => x.Name)
#Html.ValidationMessageFor(x => x.Name)
</td>
</tr>

Resources