Server Side validation not working on MVC partial view - asp.net-mvc

I have a partial view that's added to the main view via ajax call, triggered by the user clicking a button (the user clicks a button, and the partial view is added to the page).
The partial view is strongly typed to a different model than the main page. In my main page, I display the validation errors at the top, and then also have the message displayed below each field. The validation errors for my partial view are displaying at the top of the page, but they are not displaying with the field itself.
Field from partial view:
<td>
#Html.LabelFor(model => model.EmploymentCompany, "* Employer Name")
<input type="text" name="TempEmployments[#idx].EmploymentCompany" class="field panel-field" maxlength="40" style="width: 250px !important;" value="#EmploymentCompany"/>
#Html.ValidationMessage("EmploymentCompany")
</td>
Rendered as:
<td>
<label for="EmploymentCompany">* Employer Name</label>
<input type="text" name="TempEmployments[0].EmploymentCompany" class="field panel-field" maxlength="40" style="width: 250px !important;">
<span class="field-validation-valid" data-valmsg-for="EmploymentCompany" data-valmsg-replace="true"></span>
<td>
In the controller, where validation is called:
[HttpPost]
public ActionResult Create(Applicant application)
{
this.ModelState.AddModelErrors(application.Validate(update: false));
//if valid, other stuff is done. otherwise:
return View(application);
}
In the main view, where validation errors are displayed at the top:
if (!this.ViewData.ModelState.IsValid)
{
<div class="validation-summary-errors" data-valmsg-summary="true">
<ul>
#foreach (ModelState modelState in ViewData.ModelState.Values)
{
foreach (ModelError error in modelState.Errors)
{
<li>#Html.Raw(error.ErrorMessage)</li>
}
}
</ul>
</div>
}
And in the entity where validation errors are added:
foreach (var job in TempEmployments)
{
if (string.IsNullOrWhiteSpace(job.EmploymentCompany))
{
errorDictionary.Add("EmploymentCompany", "Company Name is required");
}
}
And here is what the errors look like at the top of the page:
And the partial view:

Related

MVC foreach set item.ID to model.ID

I have a form that shows all the available hotel rooms, each room has a button that does a HttpPost if clicked, I have made a property in the BookingViewModel called 'RoomID'. I would like to assign the item.RoomID to Model.RoomID so I can use it in my controller to get the id from the selected room but i'm not sure how to achieve this.
ChooseRoom View
#foreach (var item in Model.AvailableRooms)
{
<li class="room-item clearfix">
<h5>#item.Name</h5>
<div class="room-list-left">
<img src="#item.Image" alt="" />
</div>
<div class="room-list-right">
<div class="room-meta">
<ul>
<li><span>Occupancy:</span> #item.Adults Adults #item.Childs Children</li>
#if (item.SmokingRoom)
{
<li><span>Smoking Allowed:</span> Yes</li>
}
else
{
<li><span>Smoking Allowed:</span> No</li>
}
</ul>
</div>
<div class="room-price">
<p class="price">From: <span>$#item.Price</span> / Night</p>
</div>
<div class="clearboth"></div>
#using (Html.BeginForm("chooseroom", "booking", FormMethod.Post))
{
<input class="button2" type="submit" value="Select Room" />
}
BookingController
[HttpPost]
public ActionResult ChooseRoom(BookingViewModel vm)
{
BookingViewModel bookingObj = GetBooking();
bookingObj.SelectedRoom = Repository.GetRoomByID(vm.RoomID);
return View("reservation", bookingObj);
}
Thank you for your time!
update your begin form as below
#using (Html.BeginForm("chooseroom", "booking", FormMethod.Post))
{
<input type="hidden" name="RoomId" value="#item.RoomID" />
<input class="button2" type="submit" value="Select Room" />
}
Just need to provide input tags having the same name as your ViewModel property.
You could add inputs in foreach loop , it should be inside form. Something like this <input name="Model.AvailableRooms[index].RoomID" value="Id Here"/>
Or if you want to select one Room you should use ajax and post id.
If I'm not wrong you form is in loop,so you could add hidden input with id
#Html.HiddenFor(c => c.AvailableRooms[index].RoomID)

<fieldset hides when page re-loads - MVC 5

EDIT:
Here is the exact problem that I have demonstrate, please have a look and as soon as I click the submit button it post back and lost its state and as you can see in the sample code I have three pages I'm posting the form
1) EmployeeForm, 2) EmployerForm, 3) ContractorForm
https://dotnetfiddle.net/wVtwgW
How do I persist the checkbox?
Once I post the page and it reloads the same page if I have my data-model invalid and it display the error message on the screen but the problem is that, it hides the fieldset and the user has to click the checkbox again to show the fieldset.
my question is: how can I still show the fieldset and show the error message in it?
//my scripts that shows the fieldset
<script>
$(document).ready(function() {
$('#Employee').change(function() {
if (this.checked) {
$('#emp').show();
}
});
});
</script>
//it shows the fieldset with checkbox:
<fieldset class="fieldset-auto-width">
<legend>
Select Employee
</legend>
<table width="auto">
<tr>
<th>
Employee
</th>
<td>
#Html.CheckBox("Employee")
</td>
</tr>
</table>
</fieldset>
//my form where I have all the input text and button etc...
<fieldset id="emp" style="display: none" class="fieldset-auto-width">
<legend>
Employee Display
</legend>
#using (Html.BeginForm("EmployeeServer", "EmployeeForm", FormMethod.Post))
{
#Html.ValidationSummary(true)
<div>..... </div>
}
</fieldset>
Instead of using #Html.CheckBox() use #Html.CheckBoxFor()
<td>
#Html.CheckBoxFor(m => m.Employee)
</td>
this will retain the state of the checkbox when you return the model state errors..
in your javascript, just call the $("#Employee") change event after the page loads..
$(document).ready(function() {
$('#Employee').change(function() {
if (this.checked) {
$('#emp').show();
}
});
$('#Employee').trigger("change");
});
Set the Fieldset display value when view is rendered
<fieldset id="emp" style="#(Model.Employee ? "": "display: none")" class="fieldset-auto-width">
<legend>
Employee Display
</legend>
#using (Html.BeginForm("EmployeeServer", "EmployeeForm", FormMethod.Post))
{
#Html.ValidationSummary(true)
<div>..... </div>
}
</fieldset>
this will hide the fieldset if Model.Employee = false or display it if Model.Employee = true.
Just do it with JavaScript. Look for the rendered element from the validation summary helper, and if it exists then you can show your employee form. You can add it to your already executing script like this:
$(document).ready(function() {
$('#Employee').change(function() {
if (this.checked) {
$('#emp').show();
}
});
//check for validation summary elements
if($('.validation-summary-errors').length > 0){
//and show previous entry if present
$('#emp').show();
}
});

assigning button value value provided by model in asp.net MVC

I am trying to create a button for each item that is returned from my model and assign the value of the button to the column "collegeOf". My buttons display the first part of it "College" but it should be something like "College of liberal arts and sciences". I can't figure out why the value is getting truncated after the first word. Below is my code for my view:
#model IEnumerable<KU_PLAN_DEV.Models.TRACK_INFO>
#{
ViewBag.Title = "All Degree Tracks";
}
<h2>Kutztown University Degree Tracks</h2>
<div class="jumbotronAll">
#foreach (var item in Model)
{
<br />
Html.BeginForm("Index", "AllTracks");
{
<input type="submit" value=#Html.DisplayFor(modelItem => item.collegeOf) class="AllTracksButtons" />
}
}
</div>

MVC: How to insert items in a grid without refreshing the whole page

I have this view where I create a new company that gets added to the database.
The view is in 2 sections, leftside and rightside.
In the rightside I want to input the trades for that company.
A company can have 1 or more trade and this includes 1 primary trade, and 0 to many other trades.
When the user adds in the other trades, each trade will be added to a list underneath. I have NOT put in the code for this yet. For each trade in the list, he can have the option of removing it.
When he has entered all the details, he clicks submit and all the data is saved in the database.
Now I am thinking of putting in a partial view for the other trades, but I am wondering how I can do this, and every time a trade is selected from autocomplete, the data is posted to a controller method and the partial view is return.
But this will clear the data in the leftside section.
So how should I do this?
My view looks like
#model SCD.ViewModels.SubcontractorViewModel
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Create Subcontractor</legend>
<section class="wrapper">
<section class="leftside">
<table class="formTable">
<tr>
<td class="leftCell">#Html.LabelFor(model => model.Subcontractor.CompanyName)</td>
<td class="rightCell">#Html.TextBoxFor(model => model.Subcontractor.CompanyName, new { #style = "width: 300px;" })</td>
</tr>
<tr>
<td class="leftCell">#Html.LabelFor(model => model.AddressViewModel.Address1)</td>
<td class="rightCell">#Html.TextBoxFor(model => model.AddressViewModel.Address1, new { #style = "width: 300px;" })</td>
</tr>
<tr>
<td colspan="2" style="text-align: center;" class="rightCell"><input type="submit" value="Save"/></td>
</tr>
</table>
<div style="float: left">#Html.ActionLink(" ", "List", null, new { #class = "buttonBackToList" })</div>
</section>
<section class="rightside">
<table class="formTable">
<tr>
<td class="leftCell">#Html.LabelFor(model => model.PrimaryTrade)</td>
<td class="rightCell"><input type="search" name="searchPrimaryTrade" id="searchPrimaryTrade" data-scd-autocomplete="#Url.Action("AutocompletePrimaryTrade", "DataService")" style = "width: 300px;"/>
<input type="button" id="ResetPrimaryTrade" value="Reset"/>
</td>
</tr>
<tr>
<td class="leftCell">#Html.LabelFor(model => model.OtherTrades)</td>
<td class="rightCell"><input type="search" name="searchOtherTrade" id="searchOtherTrade" data-scd-autocomplete="#Url.Action("AutocompleteOtherTrade", "DataService")" style = "width: 300px;"/>
<input type="button" id="ResetOtherTrade" value="Reset"/>
</td>
</tr>
</table>
</section>
</section>
</fieldset>
}
Ajax is your answer, Whenever you do not want to reload the page then using client side ajax to communicate with the server is the only option.
I would use jQuery or to add the rows via ajax which will insert them into your database and return the populated model again and return this as a PartialView(). Your ajax would then onSuccess: replace your tableID with the returned results.
So your jQuery would be something like:
$('.rightside').children('.formTable').replaceWith(theReturnedPartialFromAjaxCall);
If you are adding a dynamic row there are two options:
On adding a row you can call an ajax request which will also add a blank row to the database and then repopulate your model and return the Partial View. This will now have the model binding in place on the new blank row, deleting the blank row or any row can also be done by ajax as the row now has an ID. Make sure however you put the ID as a hidden field in when you loop through each row.
OR (not the preferred way but probably what you will need to do as you have to perform the save)
You can capture the form collection in the save, if there are multiple rows then store this in an array
public ActionResult Save(MyModel model, FormCollection frm) {
String[] name = frm["name"].Split(',');
}
I don't like this way as it is prone to error and the first method will allow you to bind MVC's model validation

Form not submitting and no error is being produced with MVC

I have a form in my MVC application that in theory should submit data back to my database using a Repository class.
However, when I submit the form (http://localhost:1028/Admin/NewUser/), the URL changes to where the form should be submitting to, which is fine (http://localhost:1028/Admin/NewUser/Submit), but once it has been submitted, it should send the user to a confirmation page.
From what I can tell, I'm moving through all my pages correctly until it comes to the submit, where it displays the form again but under /Admin/NewUser/Submit and the data is not inserted into the database.
This is the ActionResult I'm using:
Public Function Submit() As ActionResult
Try
Dim user = New hdUser() With { _
.userLogon = Request.Form("UserLogin"), _
.userPass = Request.Form("UserPassword"), _
.userEmail = Request.Form("UserEmail"), _
.RealName = Request.Form("UserFullName"), _
.isLive = 1, _
.avatar = "noavatar.gif" _
}
userRepository.Add(user)
userRepository.Save()
Return Redirect("/Admin/NewUser/Confirm")
Catch ex As Exception
ModelState.AddModelError("Error", ex)
End Try
Return View()
End Function
I'm fairly new to MVC so I'm not entirely sure if the above is correct or not.
And in my data repository class UserRepository.vb, the two functions I'm using are:
Public Sub Add(ByVal user As hdUser) Implements IUserRepository.Add
db.hdUsers.InsertOnSubmit(user)
End Sub
and
Public Sub Save() Implements IUserRepository.Save
db.SubmitChanges()
End Sub
And the form I have created is:
<form action="/Admin/NewUser/Submit" method="post">
<table border="0" cellpadding="0" cellspacing="2">
<tr>
<td><strong>User's Full Name</strong> <br />
<%=Html.TextBox("UserFullName")%>
</td>
</tr>
<tr>
<td><strong>User Login</strong> <br />
<%=Html.TextBox("UserLogin")%>
</td>
</tr>
<tr>
<td><strong>Password</strong> <br />
<%=Html.Password("UserPassword")%>
</td>
</tr>
<tr>
<td><strong>Email Address</strong> <br />
<%=Html.TextBox("UserEmail")%>
</td>
</tr>
<tr>
<td align="right"><input type="submit" value="Create" /></td>
</tr>
</table>
</form>
The code doesn't produce any errors but also doesn't seem to be submitting to the database. So I'm not entirely sure where I've gone wrong.
It could be obvious to someone more experienced, but I really haven't a clue on this one.
Is this my code that's causing the issue or some other fault?
Thanks in advance for any help.
EDIT: Based on Zhaph - Ben Duguid comment, I have made the following edits:
AdminController.vb
<AcceptVerbs(HttpVerbs.Post)> _
Public Function NewUser(ByVal formValues As FormCollection) As ActionResult
Try
Dim user = New hdUser()
user.userLogon = Request.Form("UserLogin")
user.userPass = Request.Form("UserPassword")
user.userEmail = Request.Form("UserEmail")
user.RealName = Request.Form("UserFullName")
user.isLive = 1
user.avatar = "noavatar.gif"
UpdateModel(user)
userRepository.Add(user)
userRepository.Save()
Catch ex As Exception
ModelState.AddModelError("Error", ex)
End Try
Return View()
End Function
NewUser.aspx
<%Html.BeginForm()%>
<%=Html.ValidationMessage("Error")%>
<table border="0" cellpadding="0" cellspacing="2">
<tr>
<td><strong>User's Full Name</strong> <br />
<%=Html.TextBox("UserFullName")%>
<%=Html.ValidationMessage("Name", "*")%></td>
</tr>
<tr>
<td><strong>User Login</strong> <br />
<%=Html.TextBox("UserLogin")%>
<%=Html.ValidationMessage("Username", "*")%></td>
</tr>
<tr>
<td><strong>Password</strong> <br />
<%=Html.Password("UserPassword")%>
<%=Html.ValidationMessage("Password", "*")%></td>
</tr>
<tr>
<td><strong>Email Address</strong> <br />
<%=Html.TextBox("UserEmail")%>
<%=Html.ValidationMessage("Email", "*")%></td>
</tr>
<tr>
<td align="right"><input type="submit" value="Create" /></td>
</tr>
</table>
<% Html.EndForm() %>
Which now produces an error of The value '' is invalid. for me.
Does this mean that form values aren't being passed correctly to the controller?
EDIT: I've made those edits in response Zhaph - Ben Duguid's edit and I've changed the Form elements to the DB field names (for testing at least). And now, when the page is submitted Name, Login and Email are all filled, password is blank (which I'm assuming is expected behaviour as per password boxes) but I still receive the "The value '' is invalid" error.
Response.Write in your controller isn't going to do anything to the view.
You should be returning your model back to the edit page, with any errors in
ModelState.AddModelError();
There's a very good example of how you can implement a Repository pattern, and take advantage of the ASP.NET MVC model binding features, etc in the NerdDinner Chapter from the Professional ASP.NET MVC book.
An example controller I have (in c# I'm afraid) based on the Nerd Dinner samples:
//
// POST: /AdminAlbums/Create
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Create(FormCollection collection)
{
var album = new Album();
// Method on System.Web.Mvc.Controller, that takes a form collection, and
// using reflection on the Model, assigns values to it from the form.
UpdateModel(album);
if (album.IsValid)
{
// These methods are the same as yours
m_PhotoRepository.Add(album);
m_PhotoRepository.Save();
// In this instance, I'm returning the user to a list view of Albums
// for editing, probably ought to send them to the page to start
// uploading photos.
return RedirectToAction("Index");
}
// Still here, so I'm going to set up some ViewData I need.
ViewData["Title"] = "Create a new album";
ViewData["Message"] = "Create Album";
// I'm picking up errors from the model here.
// RuleViolation is my own class, implemented in a partial on Album.
foreach (RuleViolation violation in album.GetRuleViolations())
{
ModelState.AddModelError(violation.PropertyName, violation.ErrorMessage);
}
return View(album);
}
So you can see I return the model back to the main view if there's an error, to populate the Validation summary.
The relevant part of the view is:
<%= Html.ValidationSummary("Edit was unsuccessful. Please correct the errors and try again.") %>
<% using (Html.BeginForm()) {%>
<fieldset>
<legend>Album details</legend>
<div class="form_row">
<label for="Caption" class="left_label">Album caption:</label>
<%= Html.TextBox("Caption", Model.Caption, new { #class = "textbox" })%>
<%= Html.ValidationMessage("Caption", "*") %>
<div class="cleaner"> </div>
</div>
<div class="form_row">
<label for="IsPublic" class="left_label">Is this album public:</label>
<%= Html.CheckBox("IsPublic", Model.IsPublic) %>
</div>
<div class="form_row">
<input type="submit" value="Save" />
</div>
</fieldset>
<% } %>
Edit in response to question edit
Sorry, I should have clarified:
A lot of this is based on using the Helper methods provided by the ASP.NET MVC framework - you'll notice that I'm using methods like Html.TextBox to generate my fields, with their name/id pulled from the model itself. This way, if I load the view with ModelErrors in the ModelState, the helper will add the relevant details to rendered HTML to include the following mark-up
<label for="Caption" class="left_label">Caption:</label>
<input class="input-validation-error textbox"
id="Caption" name="Caption" type="text" value="" />
<span class="field-validation-error">*</span>
The other option you could have would be to add a message to the ViewData collection, and if it has a value, display that on your view.
Edit in response to question edit
A couple of things to bear in mind:
1) The identifiers of the Form elements and the Validation controls should be the same:
<%= Html.TextBox("Caption", Model.Caption, new { #class = "textbox" })%>
<%= Html.ValidationMessage("Caption", "*") %>
(you have things like "UserEmail" and "Email")
2) You should be returning the hdUser to the view on error - so try something like this:
<AcceptVerbs(HttpVerbs.Post)> _
Public Function NewUser(ByVal formValues As FormCollection) As ActionResult
Dim user = New hdUser()
Try
UpdateModel(user)
user.isLive = 1
user.avatar = "noavatar.gif"
userRepository.Add(user)
userRepository.Save()
Catch ex As Exception
ModelState.AddModelError("Error", ex)
End Try
Return View(user)
End Function

Resources