I'm currently experiencing a weird issue with ASP.NET MVC 3 ListBox validation, as stated in the title. Basically, I have a List in my viewmodel, which I bind to a ListBox with multiple selection enabled.
The List is given an attribute [Required]. When I submit the form with single value selected, it passes validation with no hiccups. However, with more than one, validation would fail.
Any thoughts?
Weird, I am unable to reproduce your issue.
Model:
public class MyViewModel
{
[Required(ErrorMessage = "Please select at least one item")]
public string[] SelectedItems { get; set; }
public IEnumerable<SelectListItem> Items
{
get
{
return Enumerable.Range(1, 5).Select(x => new SelectListItem
{
Value = x.ToString(),
Text = "item " + x
});
}
}
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyViewModel());
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
return View(model);
}
}
View:
#model MyViewModel
#using (Html.BeginForm())
{
#Html.ListBoxFor(x => x.SelectedItems, Model.Items)
#Html.ValidationMessageFor(x => x.SelectedItems)
<button type="submit">OK</button>
}
If you don't select any item in the list the validation error message is shown as expected. If you select one or more items the validation passes and no error message is displayed.
Related
I have a model:
public class TestModel {
[Display(Name = "Date")]
public DateTime Date { get; set; }
}
with Html.LabelFor helper method in Test.cshtml page
#Html.LabelFor(m => m.Date )
and use this page with 2 MVC action methods: Create and Update.
Example:
public virtual ViewResult Create() {
return View("Test");
}
public virtual ViewResult Update() {
return View("Test");
}
and I want to display #Html.LabelFor(m => m.Date ) with Create page: "Date" and Update page: "Update Date" . I know if the normal way of MVC3 can't do this. I hope your ideal can edit Html.LabelFor hepler method or anything way to bind data to Html.LabelFor in action methods on the controller
Adding a hiddenFor field will bind the data to your Model.
#Html.HiddenFor(m=>m.Date);
For override, please just look this answer
https://stackoverflow.com/a/5196392/5557777
you can override editorfor like this How can I override the #Html.LabelFor template? but I think you can do it more easily with ViewBag:
public virtual ViewResult Create() {
ViewBag.Title = "Create";
return View("Test");
}
public virtual ViewResult Update() {
ViewBag.Title = "Update";
return View("Test");
}
in view:
#string.format("{0} Date" , ViewBag.Title )
I've created a simple MVC application that takes information from a form and passes it to a controller
View:
#model MvcApplication1.Models.BetChargeModel
#using (Html.BeginForm())
{
<div>
#Html.TextBoxFor(m=>m.numerators[0]) / #Html.TextBoxFor(m=>m.denominators[0])
</div>
<div>
#Html.TextBoxFor(m => m.numerators[1]) / #Html.TextBoxFor(m => m.denominators[1])
</div>
<div>
<input type="submit" value="Calculate" />
</div>
}
Controller:
public ActionResult Index()
{
BetChargeModel model = new BetChargeModel();
model.numerators = new List<double>();
model.denominators = new List<double>();
model.denominators.Add(1);
model.denominators.Add(1);
model.numerators.Add(0);
model.numerators.Add(0);
return View(model);
}
[HttpPost]
public ActionResult Index(BetChargeModel model)
{
double odds1 = model.numerators[0] / model.denominators[0];
double odds = model.numerators[1] / model.denominators[1];
//other code
}
Model:
public class BetChargeModel
{
public List<double> numerators { get; set; }
public List<double> denominators { get; set; }
public double result { get; set; }
}
When I run this and try and post back information from the View the Model is coming back empty (full of null fields and zeros). Why is the data in my Textbox's not binding to the model?
(Edit: I've changed the model properties and reference to Numerators, Denominators and Result but haven't updated those here for sake of brevity)
Based on the names numerators and denominators it looks like you have implemented the lists as fields on the model.
You should use properties instead for the model binding to work properly (which I assume that #Raphael has done).
A working model would look like this:
public class BetChargeModel
{
public List<double> numerators { get; set; }
public List<double> denominators { get; set; }
}
... and to follow to naming conventions, make sure to rename numerators to Numerators and denominators to Denominators.
However, if this does not resolve your model binding issue, please elaborate and post your model implementation :)
-- UPDATE
As you have reported that the issue still persists I will post the code I have implemented based on your own provided samples - then you can cross check to make sure everything looks right on your machine - the code shown in the following is tested and works:
Model:
public class BetChargeModel
{
public List<double> numerators { get; set; }
public List<double> denominators { get; set; }
}
View:
#model Project.Models.BetChargeModel
#using (Html.BeginForm())
{
<div>
#Html.TextBoxFor(m=>m.numerators[0]) / #Html.TextBoxFor(m=>m.denominators[0])
</div>
<div>
#Html.TextBoxFor(m => m.numerators[1]) / #Html.TextBoxFor(m => m.denominators[1])
</div>
<div>
<input type="submit" value="Calculate" />
</div>
}
Controller:
public ActionResult Index()
{
var model = new BetChargeModel
{
numerators = new List<double> {0, 0},
denominators = new List<double> {1, 1}
};
return View(model);
}
[HttpPost]
public ActionResult Index(BetChargeModel model)
{
var odds1 = model.numerators[0] / model.denominators[0];
var odds = model.numerators[1] / model.denominators[1];
return null;
}
I have this code in mvc 3 razor
#using (Html.BeginForm("MyAction", "MyController"))
{
<input type="text" id="txt" name="txt"/>
<input type="image" src="image.gif" alt="" />
}
in controller I have this code
[HttpPost]
public ActionResult MyAction(string text)
{
//TODO something with text and return value...
}
now, how to send a new value, for exemple id to Action result??? Thanks
You use a view model:
public class MyViewModel
{
public string Text { get; set; }
// some other properties that you want to work with in your view ...
}
and then pass this view model to the view:
public ActionResult MyAction()
{
var model = new MyViewModel();
model.Text = "foo bar";
return View(model);
}
[HttpPost]
public ActionResult MyAction(MyViewModel model)
{
// remove the Text property from the ModelState if you intend
// to modify it in the POST controller action or HTML helpers will
// use the old value
ModelState.Remove("Text");
model.Text = "some new value";
return View(model);
}
and then the view is strongly typed to this model:
#model MyViewModel
#using (Html.BeginForm("MyAction", "MyController"))
{
#Html.EditorFor(x => x.Text)
<input type="image" src="image.gif" alt="" />
}
I try to initialize the DataView.Model in a partial view. The Page works fine but when I return to the controller the model is empty.
some help(solution or an explanation why it is not right).
thanks!!
code:
In my Partial View:
ViewData.Model = new DiamondPrint();
ViewData.Model.Diamond = m_db.DiamondInfoes.Where(di => di.Id == id).SingleOrDefault();
In my Controller:
public ActionResult Preview(DiamondPrint d)//the properties in d = null
{
return View(d);
}
Here is a great article on Model Binding. Model Binding Make sure you are setting the name property in your html input fields.
Looking at the code you have included it seems that you are initialising the ViewData.Model in the partial view but in the controller action you are expecting the default model binder to recreate your model. For the model binder to recreate your model you will need to have created a strongly typed view.
For example:
Controller:
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(IndexModel model)
{
return View();
}
Model:
public class IndexModel
{
public string MyValue { get; set; }
}
View:
Note the #model definition at the top (ignore namespace)
#model MvcApplication14.Models.IndexModel
#using (Html.BeginForm())
{
#Html.Partial("_IndexPartial", Model)
<input type="submit" value="click"/>
}
Partial View:
#model MvcApplication14.Models.IndexModel
#Html.EditorFor(m => m.MyValue)
I am trying to access the DataTypeName from the ModelMetadata in a custom DisplayTemplate, but it is always null. My goal is to make a decimal.cshtml template that looks for the DataTypeName and if it's equal to Currency format it as currency. Otherwise display the decimal like normal.
Here's an example of what I have now:
The Model:
public class MyModel
{
[DataType(DataType.Currency)]
public decimal foo { get; set; }
}
In a view that is strongly typed to MyModel I have a call like this: #Html.DisplayFor(m => m.foo)
The Display template (~/Views/Shared/DisplayTemplates/decimal.cshtml)
#model decimal?
#{
var type = ViewData.ModelMetadata.DataTypeName; // This is always null
}
I know that it's using my DisplayTemplate like it's supposed to, but I would expect the DataTypeName to not be null in this case since I have the DataType attribute on the model. Is there any way to access the DataType in a display template like this?
Strange, it should work. I am unable to reproduce. Here's what I tried in a new application:
Model:
public class MyModel
{
[DataType(DataType.Currency)]
public decimal foo { get; set; }
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new MyModel
{
foo = 12.5m
});
}
}
View (~/Views/Home/Index.cshtml):
#model MyModel
#Html.DisplayFor(x => x.foo)
Display template (~/Views/Home/DisplayTemplates/decimal.cshtml):
#model decimal?
#ViewData.ModelMetadata.DataTypeName
When I run the application it prints Currency as expected.