MvcContrib CheckBoxList - mvccontrib

May be some one could explain that behavior:
I am using CheckBoxList from the latest version of MvcContrib
When my page is loading first time - I am simply return my view
return View(Product.GetProduct(productId));
and everything seems to be fine.
All html simple controls populated successful, including checkboxlist:
<%= this.CheckBoxList(model => model.Product.Statuses)
.Options(Model.Statuses, model => model.Id, model => model.Name)
.ItemFormat("{0}<br />")
%>
So, I have a couple of buttons on this form, e.g button “Search” (). I can search by productId and display it if anything was found.
So I am passing productId to my controller and this controller returning view the same way as first time:
return View(Product.GetProduct(productId))
by the way I am using the same logic - all the same: the same view, the same controller, the same action… nothing new. But in that case I've got this error message:
String was not recognized as a valid Boolean.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.FormatException: String was not recognized as a valid Boolean.
Source Error:
Line 268: <labe**strong text**l for="group<%=item.Value%>"><%=item.Text%></label><br />
Line 269: <% } %>--%>
Line 270: <%= this.CheckBoxList(model => model.Product.Statuses).Options(Model.Statuses, model => model.Id, model => model.Name).ItemFormat("{0}<br />")%>
Line 271: </div>
Line 272: </div>
I find out, that when view is loaded first time and after, if all checkboxes unchecked I am clicking search - all going well, but when any of checkboxes checked, I am clicking search – I am getting this error.
I need help. Any bright ideas?

I believe there is a bug in CheckBoxList, such that when it validates the list it requires the values for check boxes to be boolean convertible strings ("false", "true").
So in you example if you change model => model.id to model => "true" you see that you will not get the error:
<%= this.CheckBoxList(model => model.Product.Statuses).Options(Model.Statuses, model => "true", model => model.Name).ItemFormat("{0}<br />")%>
But this is not what you want. My workaround is to remove the element for the CheckBoxList (in your case model.Product.Statuses) from ModelState when ModelState is not valid.
You need to find the corresponding key for model.Product.Statuses in ModelState and remove it. I am using the following snippet for my case. You you need to change the model and property.
if (!ModelState.IsValid)
{
ModelState.Remove(PropertyHelper<EmailModel>.GetProperty(x => x.Attachments).Name);
...
I am using PropertyHelper form How to get the PropertyInfo of a specific property?
Also I fount this relevant link in mvccontrib issue tracker:
http://mvccontrib.codeplex.com/workitem/7071

Related

MVC ModelState error "The ID field is required" although the database generates an ID

I created the MVC application database-first with the ID field being generated by the database.
Since the ID is generated by the database, in the Model I set the 'StoreGeneratedPattern' property to 'Identity'.
However, I am still getting the ModelState error "The ID field is required" when I submit a 'create' form.
I have tried restarting the solution, cleaning it, re-building it. I know that I have had this problem before, so if I figure it out I will post the answer here so that future me can find it.
For the edit view, you need to have the id in order to update the appropriate row.
If you remove #Html.HiddenFor(model => model.ID) => System will always generate new row whenever you try to edit the form.
You can follow the below code in order to reuse the same view for both create/Edit
if (model != null)
{
#Html.HiddenFor(model => model.ID)
}
=> When you try to create a form - model will be null initially so the hidden field will not be executed.
=> When you try to edit hidden field stores your id.
I had included an #Html.HiddenFor(model => model.ID) on the 'create' view.
So although the application would have gladly accepted no ID, it didn't want to accept null as the ID.
I just removed the #Html.HiddenFor and it worked.
P.S. The 'edit' view needs the #Html.HiddenFor(model => model.ID) to remember what the ID was.

Mvc 4 validation summary errors not displaying

I am having trouble displaying validation summary, I only want to display errors in validation summary, not beside the field.
In my view i have,
#Html.ValidationSummary()
#Html.ValidationMessageFor(m =>m.Name)
in my controller i have
ModelState.AddModelError("Name",
"name is required");
Am i not supposed to get a validation error message? at the top?
I don't get what i am missing...
I am also including these script files..
jquery.validate.min.js
jquery.validate.unobtrusive.min.js
Try
#Html.ValidationSummary(false)
so that it will not exclude property errors.
OR
Try the method #xurca linked which is to add the model error with an empty key so it is not tied to a specific property.
ModelState.AddModelError(String.Empty, "name is required");
If you custom named your field like
#Html.TextBoxFor(model => model.Name, new { id = "staffSearchFilterName", value = "", **Name = "staffSearchFilterName"** })
then you have to use
#Html.ValidationMessage("staffSearchFilterName")
If your #Html.ValidationSummary() call is in a Partial view, DON'T pass data into the partial view like this:
#Html.Partial("_YourForm", Model, new ViewDataDictionary { { "Submit", true }})
Instead, add the key value pair to Html.ViewData collection first:
#{
Html.ViewData.Add(new KeyValuePair<string,object>("Submit",true));
}
then call the partial view:
#Html.Partial("_YourForm", Model, Html.ViewData)
this will allow the ModelState to propagate to the partial view properly.

MVC Razor Form Validation from Render Action

I am new to MVC and trying to implement what I would expect to be a common problem. I have a simple search form that I want to implement on each page of the site. I want this section to maintain its own code so that I don't have to duplicate it on each page.
So far I have been able to do this by calling a render action on the template page. The render action populates the quicksearch form. When I submit the form I am able to validate the form, however I have not found a way to redisplay the same page with the validation information. I would prefer a way that would just refresh the form area, but I would accept a full postback as long as the page is redisplayed.
Template Render Call
#{Html.RenderAction("Display", "QuickSearch");}
ActionController
[HttpPost]
public ActionResult Submit(QuickSearchModel qsModel)
{
if (!ModelState.IsValid)
{
return PartialView(qsModel);
}
//Perform redirect
}
[ChildActionOnly]
public ActionResult Display()
{
//populate model
return View(qsModel);
}
Quick Search View
<div>
#using (Html.BeginForm("Submit", "QuickSearch"))
{
#Html.ValidationSummary(true)
#Html.LabelFor(m => m.Destination)#Html.EditorFor(m => m.Destination)#Html.ValidationMessageFor(m => m.Destination)<br />
#Html.LabelFor(m => m.ArrivalDate)#Html.EditorFor(m => m.ArrivalDate)#Html.ValidationMessageFor(m => m.ArrivalDate)
#Html.LabelFor(m => m.DepartureDate)#Html.EditorFor(m => m.DepartureDate)#Html.ValidationMessageFor(m => m.DepartureDate)<br />
#Html.LabelFor(m => m.Adults)#Html.DropDownListFor(model => model.Adults, new SelectList(Model.AdultsSelectOptions, "value", "text", Model.Adults))<br />
#Html.LabelFor(m => m.Children)#Html.DropDownListFor(model => model.Children, new SelectList(Model.ChildrenSelectOptions, "value", "text", Model.Children))<br />
<input id="qsSubmit" name="qsSubmit" type="submit" value="Submit" />
}
</div>
Thanks in advance for any assistance!
I see that you have the following problems:
How to redirect back to the page, from which the search was made?
What if this original page was "POSTed to" - that is it was rendering something, based on POST request? In this case we will not
be able to "re-produce" this POST in any easy way;
After we have redirected to the original page, how to communicate the search model (or just it's errors), which we have failed to
validate?
Given all these challenges, I would first seriously consider making this search form in AJAX style. That would be much easier solution, if it fits you.
If AJAX is not an option I see following solutions to the respective questions:
I would make a hidden field in the search form with the URL of original page. When validation fails, we can redirect to this URL (just check that it is local URL and no one tries to brake something);
This is a major problem - trying to replay original POST is not easy, but it may not be needed either - just check if this is a problem anyway;
You could use TempData dictionary to communicate errors or model back to original page.

ASP.NET MVC 2 Html.TextAreaFor not updating on Edit

I have a form that lets the user enter in some text. It will be longer than a few characters so I want to use a TextArea instead of a TextBox.
The Html.TextBoxFor works without issue, and the Html.TextAreaFor works when I create the entry, but does not store the new value when I edit it and shows whatever the value was before I went to edit it upon saving.
On Page:
<div>
<label>Work Performed:</label>
<%: Html.TextAreaFor(model => model.WorkPerformed)%>
<%: Html.ValidationMessageFor(model => model.WorkPerformed) %>
</div>
Code Behind for Create:
maintPerformed.MaintDate = DateTime.Parse(Request.Form["MaintDate"]);
maintPerformed.WorkPerformed = Request.Form["WorkPerformed"];
maintPerformedRepository.Add(maintPerformed);
maintPerformedRepository.Save();
return RedirectToAction("Details", new { id = maintPerformed.ID });
Code Behind for Edit:
maintPerformed.MaintDate = DateTime.Parse(Request.Form["MaintDate"]);
maintPerformed.WorkPerformed = Request.Form["WorkPerformed"];
maintPerformedRepository.Save();
return RedirectToAction("Details", new { id = maintPerformed.ID });
What am I missing on the edit side of things?
In both cases you are redirecting to the Details action. So make sure that maintPerformedRepository.Save() actually does something and most importantly in your Details action look what value is fetched from the data store. I suspect that either the database is not updated or in your Details action you are fetching a wrong value for your model.
Remark: Instead of writing the ugly DateTime.Parse(Request.Form["MaintDate"]); and Request.Form["WorkPerformed"]; pass your view model as argument to your controller action and let the model binder populate it from the request values.

Why do Strongly Typed Html Helpers help me?

I read ScottGu's explanation on Strongly Typed Html Helpers and I understand that it gives me the ability to do better compile time checking of views. I was under the impression that I already had this when I used the model.PropertyName in the MVC1 Html.TextBox helper, but apparently that is not true. So, how does using a lambda expression do this better for me?
Consider the syntax of the existing HTML helper methods:
<%= Html.TextBox("Quantity", Model.Quantity) %>
If you rename the Quantity property on your object to "CurrentQuantity", the generated <input> element will still have name="Quantity" specified, and model binding will break if you don't remember to change that first parameter.
By using a lambda expression to specify the name of the element, an incorrect or misspelled property name becomes a compilation error.
<!-- No magic strings here! -->
<%= Html.TextBoxFor(model => model.CurrentQuantity) %>
The improvement comes when you specify the name of the property to the helper. With strongly typed helpers, it uses the lambda expression instead of the property name to determine which property value to use.
<%= Html.TextBox( "Name" ) %>
vs
<%= Html.TextBox( m => m.Name ) %>
Textbox does not give compile time error when you wrongly mentioned the property name. it will throw run time exception.
TextBoxFor is a genetic method so it will give compile time error when you wrongly mentioned the property name.
TextBoxFor will be helpful when we append two property names in view
#Html.TextBox( "Name" ,"value",new { #class="class"})
vs
#Html.TextBoxFor( m => m.Name, new { #id="txtValue"})

Resources