MVC form submits after failing validation - asp.net-mvc-3

This has been asked and answered 100 times, and I have read them all, yet still my form submits after failing validation. I found a reference to not using jquery.validate higher than 1.9.0, so I rolled back to that (had been using 1.11) but no change.
If i submit with an invalid form (nothing filled out) the error messages appear, then the form submits.
I have successfully implemented validation a couple times in the past, and I can't see what is different about this time. I need to take a break from banging my head against this, hoping a fresh pair of eyes may see something.
--Scripts:
<script src="#Url.Content("~/Scripts/jquery-1.9.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/modernizr-1.7.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery-ui-1.10.1.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
Model:
[Display(Name = "First Name *")]
[StringLength(20)]
[Required(ErrorMessage = "Required.")]
public string FirstName { get; set; }
[Remote("CheckDuplicatePerson", "Validation", AdditionalFields = "FirstName", ErrorMessage="Person Exists")]
[Display(Name = "Last Name *")]
[StringLength(30)]
[Required(ErrorMessage = "Required.")]
public string LastName { get; set; }
View:
<div class="PersonForm">
#using (Html.BeginForm("AddPerson", "Person", FormMethod.Post))
{ #Html.ValidationSummary(true)
<div id="editor-left">
<div class="formGroup">
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName) <br />
#Html.ValidationMessageFor(model => model.FirstName)
</div>
</div>
<div class="formGroup">
<div class="editor-label">
#Html.LabelFor(model => model.MiddleName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.MiddleName)
</div>
</div>
<div class="formGroup">
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName) <br />
#Html.ValidationMessageFor(model => model.LastName)
</div>
</div>
<div class="controls"><hr />
<input type="submit" class="skbutton" value="Next Page" />
</div>
}
</div>
UPDATE:
Get a JS Error in the jquery 1.9.1 file on this peice of code:
parseJSON: function( data ) {
// Attempt to parse using the native JSON parser first
if ( window.JSON && window.JSON.parse ) {
return window.JSON.parse( data );
}

Finally got it working.
#Jerad, I tried removing the remote validation, no help.
Turned out it was the microsoft unobtrusive script. I updated that and it started working. There seems to be a fine line of dependancies with all this stuff. Here are my versions that are working:
jquery-1.9.1
jquery.unobtrusive-ajax - 3.1.1
jquery.validate - 1.11.1
jquery.validate.unobtrusive - 3.1.1
Thank you all for your input.

I had a similar problem. Putting #Html.ValidationMessageFor(model => model.FieldName) for every input field somehow fixed the problem

Related

How to make this into a checkbox?

So I have a view as such:
#model Tuple<LocApp.Models.Location, LocApp.Models.Service>
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Location</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Item1.name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item1.name)
#Html.ValidationMessageFor(model => model.Item1.name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Item1.active)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Item1.active)
#Html.ValidationMessageFor(model => model.Item1.active)
</div>
#Html.CheckBoxFor(model => model.Item2.id)
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
and the line: #Html.CheckBoxFor(model => model.Item2.id) IMO is suppose to go through and for every service in the database create a check box based on the id so I can then save the id. How ever, apparently I must pass in a boolean value? the only one I have is model.Item2.active
Ideas?
CheckBoxes can only have boolean states: Checked or Unchecked. Your model must set a checkbox state by using a boolean value of true or false. If you want your checkbox to act as the mechanism for saving an Id to your database, you need to write business logic for checking if the checkbox is checked on the controller action. If the checkbox is checked, write the Id, otherwise don't write the Id.
You should have a bool model.Item1.checked (or active, enabled, etc), then use that instead of model.Item1.id, it will keep track of whether the flag is on or off for that item.
Then when they POST the form you can loop through (or use LINQ) all the items and save the id for each one that has .checked = true.

HttpPost method is not fired if the submit button is disabled

I have a view as follows: DemoView.cshtml
#model Mvc3Razor.Models.UserModel
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>
Create</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>UserModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FirstName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FirstName)
#Html.ValidationMessageFor(model => model.FirstName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LastName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LastName)
#Html.ValidationMessageFor(model => model.LastName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.City)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.City)
#Html.ValidationMessageFor(model => model.City)
</div>
<p>
<input type="submit" value="Create" /></p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<script type="text/javascript">
$(function () {
$('input[type="submit"]').click(function () {
$(this).attr('disabled', 'disabled');
});
});
</script>
And a controller: HomeController.cs
[HttpPost]
public ViewResult Create(UserModel um)
{
if (!TryUpdateModel(um))
{
ViewBag.updateError = "Create Failure";
return View(um);
}
_usrs.Create(um);
return View("Details", um);
}
In order to prevent multiple button clicks, I am trying to disable the button once user clicks the Create button but once the Create button is disabled it is not firing the HttpPost method.
Can anyone help me out in order to resolve this issue?
Try disabling the button when the form is submitted and not when the submit button is clicked:
$("form").submit(function() {
$(this).attr("disabled", "disabled");
return true;
});
What I will suggest is to redirect user back to Index Page upon Successfull Post. You want use PRG Pattern
Post, Redirect, Get (PRG) pattern in which it is "to help avoid
duplicate form submissions and allow web applications to behave more
intuitively with browser bookmarks and the reload button"
usrs.Create(um);
//Redirect to Index Page here
see this SO question for more details

MVC3 view rendering twice when I have Glimpse and use a MVC control toolkit DateTimeFor element

I have an MVC application with glimpse installed, I am also using the MVCControlToolkit for dymanic validation.
The issue I have is when I have a view that uses DateTimeFor to display the date time calendar with validation, but only in a very limited set of circumstances (if I only have datetimefor elements this doesn't happen), the body gets rendered on the page twice.
It looks like the rendering is getting restarted by something, but I haven't been able to work it out.
Any help would be appreciated
My view code is
#using LeaveTracker.Models
#using LeaveTracker.Models.Leave
#using MVCControlsToolkit.Controls
#using MVCControlsToolkit.Controls.Validation
#model LeaveTracker.Models.Leave.LeaveAllocation
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_LayoutMaintenance.cshtml";
}
#Html.AntiForgeryToken()
<div class="page-header">
<h1>
Edit Leave Allocation
#if (Model.ID > 0) { <small> #Model.TypeOfLeave.Name till #Model.AppliesUntil.ToString("dd/MM/yyyy")</small> }
</h1>
</div>
<div>
#Html.ActionLink("Back to List", "Index")
</div>
<link href="#Url.Content("~/Content/themes/base/jquery-ui.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/themes/base/jquery.ui.datepicker.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-ui-1.8.16.min.js")" type="text/javascript"></script>
#Html.JQueryDatePickerGlobalizationScript("en-GB")
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/ValidationSetup.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/MVCControlToolkit.Controls-1.5.0.js")" type="text/javascript"></script>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Leave Allocation Details</legend>
#Html.HiddenFor(model => model.ID)
<div class="clearfix">
#Html.LabelFor(model => model.TypeOfLeave)
<div class="input">
#Html.DropDownListFor(model => model.TypeOfLeave,
LeaveFactory.GetAllLeaveTypes().Select(fl => new SelectListItem
{
Text = fl.Name,
Value = fl.ID.ToString()
}))
<span class="help-inline">#Html.ValidationMessageFor(model => model.TypeOfLeave)</span>
</div>
</div>
<div class="clearfix">
#Html.LabelFor(model => model.AppliesFrom)
<div class="input">
#Html.DateTimeFor(model => model.AppliesFrom, DateTime.Today, true).DateCalendar(
inLine: false,
calendarOptions: new CalendarOptions
{
ChangeYear = true,
ChangeMonth = true
})
<span class="help-inline">#Html.ValidationMessageFor(model => model.AppliesFrom)</span>
</div>
</div>
<div class="clearfix">
#Html.LabelFor(model => model.AppliesUntil)
<div class="input">
#Html.DateTimeFor(model => model.AppliesUntil, DateTime.Today, true).DateCalendar(
inLine: false,
calendarOptions: new CalendarOptions
{
ChangeYear = true,
ChangeMonth = true
})
<span class="help-inline">#Html.ValidationMessageFor(model => model.AppliesUntil)</span>
</div>
</div>
<div class="clearfix">
#Html.LabelFor(model => model.DefaultAllocation)
<div class="input">
#Html.EditorFor(model => model.DefaultAllocation)
<span class="help-inline">#Html.ValidationMessageFor(model => model.DefaultAllocation)</span>
</div>
</div>
</fieldset>
<fieldset>
<legend>Leave Carried Over</legend>
<div class="clearfix">
#Html.LabelFor(model => model.MaxCarriesOver)
<div class="input">
#Html.EditorFor(model => model.MaxCarriesOver)
<span class="help-inline">#Html.ValidationMessageFor(model => model.MaxCarriesOver)</span>
</div>
</div>
<div class="clearfix">
#Html.LabelFor(model => model.LeaveUseByDate)
<div class="input">
#Html.DateTimeFor(model => model.LeaveUseByDate, DateTime.Parse("01/01/1900"), true).DateCalendar(
inLine: false,
calendarOptions: new CalendarOptions
{
ChangeYear = true,
ChangeMonth = true
})
<span class="help-inline">#Html.ValidationMessageFor(model => model.LeaveUseByDate)</span>
<span class="help-block">The year on this field doesn't matter, only the month and day will be taken into account</span>
</div>
</div>
<div class="actions">
#Html.ActionLink("Cancel", "Index", null, new { #class = "btn" })
<input class="btn primary" type="submit" value='Save'>
</div>
</fieldset>
}
Lee,
We believe we have fixed this issue.
Can you please test and confirm by installing the alpha build of Glimpse 0.87 from MyGet at http://www.myget.org/F/getglimpse/
If we get confirmation that this fixes your issue - and with a bit more testing - we will release to the main NuGet.org repository.
EDIT
Glimpse version 0.87 is now available from the main NuGet.org Glimpse feed

how can i get the value selected in #Html.DropDownList in a MVC3

I have this code, how can I get the selected value of the #htmlDropDownList to put this value in my #Url.Action instead of 1, I have read using javascript o jquery but i cant figure out how can i do that in the view directly, and this is not working for my
var idempresa = $('IdEmpresa').val()
<a href="#Url.Action("List","Script")?idempresa=**idempresa**"
the code:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Script</legend>
<div class="editor-label">
#Html.LabelFor(model => model.IdEmpresa, "Empresa")
</div>
<div class="editor-field">
#Html.DropDownList("IdEmpresa", String.Empty )
#Html.ValidationMessageFor(model => model.IdEmpresa)
</div>
</fieldset>
}
href="#Url.Action("List","Script")?idempresa=**1**"
pd. thank you for the help
Edit:
#using System.Web.Mvc.Html
#model SistemaDispositivos.Models.Script
#{
ViewBag.Title = "Script";
}
<h2>Script</h2>
<script src="../../Scripts/jquery-1.6.2.min.js" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Script</legend>
<div class="editor-label">
#Html.LabelFor(model => model.IdEmpresa, "Empresa")
</div>
<div class="editor-field">
#Html.DropDownList("IdEmpresa", String.Empty)
#Html.ValidationMessageFor(model => model.IdEmpresa)
</div>
</fieldset>
}
<script type="text/javascript" language="javascript">
$(document).ready(function () {
var url1 = '#Url.Action("List","Script")?idempresa=';
$('IdEmpresa').change(function() {
$urlId = $('urlid');
$urlId.attr('href', url + $(this).val());
});
});
</script>
<a id="urlid" href="#Url.Action("List","Script")?idempresa=url1"> </a>
What iam missing?
well it work now this is what I wanted thank for the help:
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Script</legend>
<div class="editor-label">
#Html.LabelFor(model => model.IdEmpresa, "Empresa")
</div>
<div class="editor-field">
#Html.DropDownList("IdEmpresa", string.Empty )
#Html.ValidationMessageFor(model => model.IdEmpresa)
</div>
</fieldset>
}
<script type="text/javascript" language="javascript">
function valid() {
var listaScriptUrl = '#Url.Action("List", "Script", new { idempresa = 0})';
var input = $('#IdEmpresa').val();
$('#Lista-Script').load(listaScriptUrl.replace('0', input));
}
</script>
<input type="button" value="Click Here" onclick="valid()">
<div id="Lista-Script">
</div>
so now in the div Lista-Script when I click the button I get my view that I wanted
The view would render HTML so you cannot get the selected value of dropdown list and put it back to the variable of the view which has already executed in the server side. What you could do is put an id on the tag and update the href on change event of dropdown.
$(document).ready(function(){
$('IdEmpresa').change(function(){
var val = $(this).val();
var newurl = $("urlid").attr("href") + val;
$("urlid").attr("href",newurl);
});
});
<a id="urlid" href="#Url.Action("List","Script")?idempresa="> </a>
I would approach this much like Bipins posted, with one major exception.
<fieldset>
<legend>Script</legend>
<div class="editor-label">
#Html.LabelFor(model => model.IdEmpresa, "Empresa")
</div>
<div class="editor-field">
#Html.DropDownList("IdEmpresa", *This needs to be a list of ListItems*, new { id = "idEmpresa" })
#Html.ValidationMessageFor(model => model.IdEmpresa)
</div>
</fieldset>
$(document).ready(function()
{
var url = '#Url.Action("List","Script")?idempresa=';
$('#idEmpresa').change(function()
{
$urlId = $('urlid');
$urlId.attr('href', $urlId.attr('href') + $('this').val());
}
});
By caching the original URL in a js variable, you always have a clean slate to append to.

MVC 3 Razor AJAX doesn't work

In EditPhoto.cshtml:
#model vg_music.Models.images
#{
ViewBag.Title = "EditPhoto";
}
<h2>
EditPhoto2</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Ajax.BeginForm(new AjaxOptions{UpdateTargetId = "AjaxDiv"})) {
#Html.ValidationSummary(true)
<div id="AjaxDiv">
#Html.Partial("EditPhotoForm")
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
EditPhotoForm.cshtml:
#model vg_music.Models.images
<fieldset>
<legend>images</legend>
#Html.HiddenFor(model => model.id)
<div class="editor-label">
#Html.LabelFor(model => model.title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.title)
#Html.ValidationMessageFor(model => model.title)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.comment)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.comment)
#Html.ValidationMessageFor(model => model.comment)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.filename)
</div>
<div class="editor-field">
<img src="#Url.Content("~/uploads/images/little/"+Model.filename)" alt="#Model.title"/><br />
</div>
<p>
<input type="submit" value="Сохранить" />
</p>
</fieldset>
PhotosController.cs:
....
[HttpPost]
public ActionResult EditPhoto(images obj)
{
if (ModelState.IsValid)
{
var db = new EditImagesModel();
db.SaveImage(obj);
if (Request.IsAjaxRequest()) //This does not work.
{
return PartialView("EditPhotoForm");
}
return RedirectToAction("EditPhotos");
}
return View();
}
....
Why is not satisfied:
if (Request.IsAjaxRequest())
{
return PartialView("EditPhotoForm");
}
Why is not satisfied:
Because you forgot to include:
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
in your EditPhoto.cshtml page. And because of this the Ajax.BeginForm helper doesn't perform any AJAX request but a simple form POST.
Contrary to ASP.NET MVC 1.0 and 2.0 where Ajax.* helpers such as Ajax.ActionLink and Ajax.BeginForm were polluting your markup with javascript obtrusively, in ASP.NET MVC 3 they simply generate HTML5 data-* attributes on the corresponding DOM elements. This way markup and javascript is kept separate. And you need javascript to interpret those attributes. This javascript is located in the jquery.unobtrusive-ajax.js script which needs to be included.

Resources