MVC3 Client Side Validation not working with an Ajax.BeginForm form - asp.net-mvc-3

I have the following form in a partial view
#model PartDetail
#using (Ajax.BeginForm("Create", "Part", null, new AjaxOptions { UpdateTargetId = "update_panel"}))
{
<h3>New #Model.PartType</h3>
<p> Serial Number:
<strong>
#Html.EditorFor(model => model.SerialNumber)
#Html.ValidationMessageFor(model => model.SerialNumber)
</strong>
</p>
<p> Name:
<strong>
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</strong>
</p>
...... more relatively boiler plate code here......
<p>
<input type="submit" class="btn primary" value="Save Part"/>
</p>
}
With a model of
public class PartDetail
{
public string DateCreated { get; set; }
[StringLength(255, MinimumLength = 3)]
public string Description { get; set; }
public Guid ID { get; set; }
public string IsActive { get; set; }
public string Manufacturer { get; set; }
public IEnumerable<SelectListItem> Manufacturers { get; set; }
[StringLength(100, MinimumLength = 3)]
public string Name { get; set; }
public string PartType { get; set; }
[Required]
[StringLength(100, MinimumLength = 3)]
public string SerialNumber { get; set; }
}
And I reference (in parent views of my partial view)
<script src="#Url.Content("~/Scripts/jquery-1.7.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.js")" type="text/javascript"> </script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"> </script>
And nothing gets validated. If I type nothing into the Serial Number text box and press submit it saves it to the database with no problems.

Try adding an OnBegin callback to the AjaxOptions and this should work.
function validateForm() {
return $('form').validate().form();
}
#using (Ajax.BeginForm("Create", "Part", null, new AjaxOptions { UpdateTargetId = "update_panel", OnBegin = "validateForm" }))
...
If this doesn't work for you, an alternative solution may be to submit the form using jQuery. This would be my preferred solution.
<div id="result"></div>
#using (Html.BeginForm())
{
<h3>New #Model.PartType</h3>
<p>Serial Number:
<strong>
#Html.EditorFor(model => model.SerialNumber)
#Html.ValidationMessageFor(model => model.SerialNumber)
</strong>
</p>
<p> Name:
<strong>
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</strong>
</p>
...... more relatively boiler plate code here......
<p>
<input type="submit" class="btn primary" value="Save Part"/>
</p>
}
jQuery/JS function to submit the form
$(function () {
$('form').submit(function () {
$.validator.unobtrusive.parse($('form')); //added
if ($(this).valid()) {
$.ajax({
url: this.action,
type: this.method,
data: $(this).serialize(),
success: function (result) {
$('#result').html(result);
}
});
}
return false;
});
});

In this case order of javascript file including process is important. Your order of including these file should be
jquery.js
jquery.validate.js
jquery.validate.unobtrusive.js
When I tried with re-ordering it works fine for me. Try it.

Check your root Web.config of the solution/project. Does it contain the following lines?
<appSettings>
<add key="ClientValidationEnabled" value="true"/>
<add key="UnobtrusiveJavaScriptEnabled" value="true"/>
</appSettings>
It not, add them.

you need to modified your controller action little bit to work validation in Ajax request
you catch RenderHtml of partial view and apply your validation on it for e.g
//In Controller
public string Create(PartDetail model)
{
string RenderHtml = RenderPartialViewToString("PartailViewName", model);
return RenderHtml;
}
protected string RenderPartialViewToString(string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = ControllerContext.RouteData.GetRequiredString("action");
ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
you must be pass ViewName and Model to RenderPartialViewToString method. it will return you view with validation which are you applied in model.

Related

ASP.NET MVC Ajax file upload with jquery form plugin?

I use Jquery Ajax Form Plugin to upload file. Codes:
AuthorViewModel
public class AuthorViewModel
{
public int Id { get; set; }
[Required(ErrorMessage = "{0} alanı boş bırakılmamalıdır!")]
[Display(Name = "Yazar Adı")]
public string Name { get; set; }
[Display(Name = "Kısa Özgeçmiş")]
public string Description { get; set; }
[Display(Name = "E-Posta")]
public string Email { get; set; }
public string OrginalImageUrl { get; set; }
public string SmallImageUrl { get; set; }
}
Form
#using (Html.BeginForm("_AddAuthor", "Authors", FormMethod.Post, new { id = "form_author", enctype = "multipart/form-data" }))
{
<div class="editor-label">
<input type="file" name="file" id="file" />
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
</div>
<div class="editor-field">
#Html.ValidationMessageFor(model => model.Name)
</div>
...
<div class="submit-field">
<input type="submit" value="Ekle" class="button_gray" />
</div>
}
Script
<script>
$(function () {
$('#form_author').ajaxForm({
beforeSubmit: ShowRequest,
success: SubmitSuccesful,
error: AjaxError
});
});
function ShowRequest(formData, jqForm, options) {
$(".loading_container img").show();
}
function AjaxError() {
alert("An AJAX error occured.");
}
function SubmitSuccesful(result, statusText) {
// Veritabanı işlemleri başarılı ise Index sayfasına
// geri dön, değilse partial-view sayfasını yenile
if (result.url) {
window.location.href = result.url;
} else {
$(".authors_content_container").html(result);
}
}
</script>
Controller
[HttpPost]
public ActionResult _AddAuthor(AuthorViewModel viewModel, HttpPostedFileBase file)
{
...
viewModel.OrginalImageUrl = file.FileName;
...
}
Above codes work fine
Question
As you see, I post file seperate from ViewModel. Is there a way to add HttpPostedFileBase file property to ViewModel and bind it to viewModel in view, And post it to controller in ViewModel?
I hope , I can explain.
EDIT:
This codes work fine. I dont want post , viewModel and HttpPostedFile seperately. I want something like this: (If it is possible.)
Model
public class AuthorViewModel
{
public int Id { get; set; }
[Required(ErrorMessage = "{0} alanı boş bırakılmamalıdır!")]
[Display(Name = "Yazar Adı")]
HttpPostedFileBase file{ get; set; }
...
}
Controller
[HttpPost]
public ActionResult _AddAuthor(AuthorViewModel viewModel)
{
var file = viewModel.file;
...
}
Thanks.
Yes you can add AliRıza Adıyahşi.
Here is the property to do it:
public HttpPostedFileBase File { get; set; }
Now in you form you should add enctype as Xiaochuan Ma said:
#using (Html.BeginForm("_AddAuthor", "Authors", FormMethod.Post, new { id = "form_author", enctype="multipart/form-data" }))
{
<div class="editor-label">
<input type="file" name="file" id="file" />
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
</div>
<div class="editor-field">
#Html.ValidationMessageFor(model => model.Name)
</div>
...
<div class="submit-field">
<input type="submit" value="Ekle" class="button_gray" />
</div>
}
On you Controller action:
[HttpPost]
public ActionResult _AddAuthor(AuthorViewModel viewModel, HttpPostedFileBase file)
{
if(file!=null)
{
viewModel.File=file; //Binding your file to viewModel property
}
//Now you can check for model state is valid or not.
if(ModelState.IsValid)
{
//do something
}
else
{
return View(viewModel);
}
}
Hope it helps. Is this what you need ?
EDIT
There is nothing additional to do. Its automatically binding to viewModel.
[HttpPost]
public ActionResult _AddAuthor(AuthorViewModel viewModel)
{
var uploadedfile = viewModel.File;// Here you can get the uploaded file.
//Now you can check for model state is valid or not.
if(ModelState.IsValid)
{
//do something
}
else
{
return View(viewModel);
}
}
This worked for me !
Yes, you can add HttpPostedFileBase in to your ViewModel, and add enctype = "multipart/form-data" to your From in HTML.
Check with this link:
MVC. HttpPostedFileBase is always null

Asp.net mvc 3 model doesn't get automatically bind?

I'm studying asp.net mvc 3 right now and I'm following this tutorial Contoso University
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/handling-concurrency-with-the-entity-framework-in-an-asp-net-mvc-application
I'm in this part where editing a model is handled with Optimistic Concurrency
I'm aware that by using something like
[HttpPost]
public ActionResult Edit(Department department)
the model will automatically be binded, even without a hidden field for the id of the department to be edited, and the edit will not fail.
But whenever I try to remove the two hiddenfields in the view of this one:
#model MvcContosoUniversity.Models.Department
#{
ViewBag.Title = "Edit";
}
<h2>Edit</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>Department</legend>
#Html.HiddenFor(model => model.DepartmentID)
#Html.HiddenFor(model => model.Timestamp)
<div class="editor-label">
#Html.LabelFor(model => model.Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Name)
#Html.ValidationMessageFor(model => model.Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Budget)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Budget)
#Html.ValidationMessageFor(model => model.Budget)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.StartDate)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.StartDate)
#Html.ValidationMessageFor(model => model.StartDate)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.InstructorID, "Administrator")
</div>
<div class="editor-field">
#Html.DropDownList("InstructorID", String.Empty)
#Html.ValidationMessageFor(model => model.InstructorID)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
I get an error in the controller, here's the code for the controller:
// GET: /Department/Edit/5
public ActionResult Edit(int id)
{
Department department = db.Departments.Find(id);
ViewBag.InstructorID = new SelectList(db.Instructors, "InstructorID", "FullName", department.InstructorID);
return View(department);
}
//
// POST: /Department/Edit/5
[HttpPost]
public ActionResult Edit(Department department)
{
try
{
if (ModelState.IsValid)
{
db.Entry(department).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DbUpdateConcurrencyException ex)
{
var entry = ex.Entries.Single();
//Another option is to put the try-catch inside a function
try
{
var databaseValues = (Department)entry.GetDatabaseValues().ToObject();
var clientValues = (Department)entry.Entity;
if (databaseValues.Name != clientValues.Name)
ModelState.AddModelError("Name", "Current value: "
+ databaseValues.Name);
if (databaseValues.Budget != clientValues.Budget)
ModelState.AddModelError("Budget", "Current value: "
+ String.Format("{0:c}", databaseValues.Budget));
if (databaseValues.StartDate != clientValues.StartDate)
ModelState.AddModelError("StartDate", "Current value: "
+ String.Format("{0:d}", databaseValues.StartDate));
if (databaseValues.InstructorID != clientValues.InstructorID)
ModelState.AddModelError("InstructorID", "Current value: "
+ db.Instructors.Find(databaseValues.InstructorID).FullName);
ModelState.AddModelError(string.Empty, "The record you attempted to edit "
+ "was modified by another user after you got the original value. The "
+ "edit operation was canceled and the current values in the database "
+ "have been displayed. If you still want to edit this record, click "
+ "the Save button again. Otherwise click the Back to List hyperlink.");
department.Timestamp = databaseValues.Timestamp;
}
catch(NullReferenceException e)
{
ModelState.AddModelError("","Error \n "+e.Message);
}
}
catch (DataException)
{
//Log the error (add a variable name after Exception)
ModelState.AddModelError(string.Empty, "Unable to save changes. Try again, and if the problem persists contact your system administrator.");
}
ViewBag.InstructorID = new SelectList(db.Instructors, "InstructorID", "FullName", department.InstructorID);
return View(department);
}
Here is the code for the model:
public class Department
{
public int DepartmentID { get; set; }
[Required(ErrorMessage = "Department name is required.")]
[MaxLength(50)]
public string Name { get; set; }
[DisplayFormat(DataFormatString = "{0:c}")]
[Required(ErrorMessage = "Budget is required.")]
[Column(TypeName = "money")]
public decimal? Budget { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[Required(ErrorMessage = "Start date is required.")]
public DateTime StartDate { get; set; }
[Display(Name = "Administrator")]
public int? InstructorID { get; set; }
public virtual Instructor Administrator { get; set; }
public virtual ICollection<Course> Courses { get; set; }
[Timestamp]
public Byte[] Timestamp { get; set; }
}
Is it possible to make it work without using hiddenfields?
Sir/Ma'am your answers would be of great help. Thank you++
Based on your HttpPost action signature, no, this isn't possible. You're performing an Edit so it will need the Id of the row that is being updated. Since you're not mapping the Id in the action method signature, and the hidden fields holding that information aren't there, the id will never get mapped to the Department model. The result being that you would try to perform an update without a row id.
EDIT: You could modify your action signature like so: Edit(int id, Department department), but then you'd have to manually set the department.Id to the id passed and that would seem to make the model somewhat disjointed.

Why are my required attributes of my model not work in MVC3

In my class file where my model is I have required attributes such as:
[Required]
[Range(0, 99, ErrorMessage = "Sorry, you must select a range between 0 - 99.")]
public int MaxConcurrentUsers { get; set; }
So you would think that when I click the submit button on the page to post the values, that because I have typed an incorrect value for MaxConcurrentUsers it wouldn't reach the actionResult method in my C# code. But it does. One thing I have noticed is that my modelstate .valid is false, but I want the client to stop it from getting to that method. What am I doing wrong?
My model
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated from a template.
//
// Manual changes to this file may cause unexpected behavior in your application.
// Manual changes to this file will be overwritten if the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace UserManager.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public partial class vw_UserManager_Model
{
public string rowtype { get; set; }
public System.Guid applicationid { get; set; }
public System.Guid userid { get; set; }
// [StringLength(12, MinimumLength = 6,
//ErrorMessage = "Username must be between 6 and 12 characters.")]
public string UserName { get; set; }
[Required]
[Range(0, 99, ErrorMessage = "Sorry, you must select a range between 0 - 99.")]
public int MaxConcurrentUsers { get; set; }
[Required(ErrorMessage = "First name is a required field")]
[Display(Name = "First name")]
public string firstname { get; set; }
[Required(ErrorMessage = "Last name is a required field")]
[Display(Name = "Last name")]
public string lastname { get; set; }
public string salutation { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string password { get; set; }
[Required(ErrorMessage = "Email is required.")]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string email { get; set; }
public string group_name { get; set; }
public Nullable<long> group_id { get; set; }
public int moduleid { get; set; }
public Nullable<int> session_status { get; set; }
public Nullable<int> islockedout { get; set; }
public Nullable<bool> isactive { get; set; }
public bool IsApproved { get; set; }
public bool alf { get; set; }
public bool brad { get; set; }
public string module_name { get; set; }
public string CompanyName { get; set; }
public string CompanySearch { get; set; }
public string selected_module { get; set; }
public string selected_group { get; set; }
public string selected_moduleAlf { get; set; }
public string selected_moduleBrad { get; set; }
public string selected_groupAlf { get; set; }
public string selected_groupBrad { get; set; }
}
}
My view
#model UserManager.Models.vw_UserManager_Model
<h2 style="padding-left: 25px;">
Create user</h2>
#using (Html.BeginForm())
{
<!-- ALF/BRAD selection -->
#Html.ValidationSummary(true)
<fieldset style="width: 400px; padding-left: 15px;">
<legend>Select module type:</legend>
<div class="module-selection">
#Html.Label("Select ALF")
<input type="checkbox" checked="checked" id="chkAlf" name="selection" value="Alf"
onclick="chkSelection()" />
#Html.Label("Select BRAD")
<input type="checkbox" id="chkBrad" name="selection" value="Brad" onclick="chkSelection()" />
</div>
</fieldset>
<!-- Module selection -->
<fieldset style="width: 400px; padding-left: 15px;">
<legend>Select module:</legend>
<div id="alfModules">
#{Html.RenderAction("_CreateUserModulesAlf", "UserManager");}
</div>
<br />
<div id="bradModules">
#{Html.RenderAction("_CreateUserModulesBrad", "UserManager");}
</div>
</fieldset>
<!-- Check if group exists -->
<fieldset style="width: 400px; padding-left: 15px;">
<legend>Group Checker</legend>
<div id="createuser-groupnamesearch">
#{Html.RenderAction("_txtGroupSearchForm", "UserManager");}
</div>
</fieldset>
<fieldset style="width: 400px; padding-left: 15px;">
<legend>New User Details</legend>
<div class="editor-label">
#Html.LabelFor(Model => Model.salutation)
</div>
<div class="editor-field">
#Html.DropDownListFor(Model => Model.salutation, new List<SelectListItem>
{
new SelectListItem{ Text="Mr", Value = "Mr" },
new SelectListItem{ Text="Mrs", Value = "Mrs" },
new SelectListItem{ Text="Miss", Value = "Miss" },
new SelectListItem{ Text="Ms", Value = "Ms" },
new SelectListItem{ Text="Dr", Value = "Dr" }
})
#Html.ValidationMessageFor(model => Model.salutation)
</div>
<div id="createuser-usernamesearch">
#{Html.RenderAction("_txtUsernameSearch", "UserManager");}
</div>
<div class="editor-label">
#Html.Label("Firstname")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.firstname)
#Html.ValidationMessageFor(model => Model.firstname)
</div>
<div class="editor-label">
#Html.Label("Surname")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.lastname)
#Html.ValidationMessageFor(model => Model.lastname)
</div>
<div class="editor-label">
#Html.Label("Password")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.password)
#Html.ValidationMessageFor(model => Model.password)
</div>
<div class="editor-label">
#Html.Label("Email")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.email)
#Html.ValidationMessageFor(model => Model.email)
</div>
<div class="editor-label">
#Html.Label("Is active")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.isactive)
#Html.ValidationMessageFor(model => Model.isactive)
</div>
<div class="editor-label">
#Html.Label("Maximum concurrent users")
</div>
<div class="editor-field">
#Html.EditorFor(model => Model.MaxConcurrentUsers)
#Html.ValidationMessageFor(model => Model.MaxConcurrentUsers, "Enter a number between 0-99.")
</div>
<div id="moduleSelection">
#Html.HiddenFor(Model => Model.selected_moduleAlf, new { id = "hdnModuleAlf" })
#Html.HiddenFor(Model => Model.selected_moduleBrad, new { id = "hdnModuleBrad" })
</div>
<input type="submit" value="Create" onclick="return submitWith();" />
<span id="validationMessage"></span>
<br />
<br />
#Html.ActionLink("Back to List", "Index")
</fieldset>
<div>
#Html.ValidationSummary()
</div>
}
<script type="text/javascript">
// Count checkboxes that are checked.
function submitWith() {
var checkedCount = $("input:checked").length;
var valid = checkedCount > 0;
// Check that one checkbox is checked first
if (!valid) { // IF false
$('#validationMessage').html('You must select at least one option').css("background-color", "red");
}
// Second check ALF
else if ($('.module-selection #chkAlf').is(':checked')) {
if ($("#txtGroupnameExistsAlf").val() == "Alf Group doesn't exist.") {
valid = false;
$('#validationMessage').html('Group must exist in ALF Database first').css("background-color", "red");
}
if ($("#txtGroupnameExistsAlf").val() == "") {
valid = false;
$('#validationMessage').html('A group must be picked when creating a new user.').css("background-color", "red");
}
}
// Third check
else if ($('.module-selection #chkBrad').is(':checked')) {
if ($("#txtGroupnameExistsBrad").val() == "Brad Group doesn't exist.") {
valid = false;
$('#validationMessage').html('Group must exist in BRAD Database first').css("background-color", "red");
}
if ($("#txtGroupnameExistsBrad").val() == "") {
valid = false;
$('#validationMessage').html('A group must be picked when creating a new user.').css("background-color", "red");
}
}
else {
valid = true;
}
return valid;
}
function chkSelection() {
// alert("check selection");
filters = new Object();
if ($('.module-selection #chkAlf').is(':checked')) {
// Show Div
$("#alfModules").show();
$("#groupname-checker-alf").show();
// Show username checker for Alf
$("#username-checker-alf").show();
// Set ALF model property to true
$("#hdnAlf").val("true");
// Set alf value for one to be passed to Ajax request
filters.alf = 1;
var selectedVal = $("#ddlSelectedAlf :selected").val();
$('#hdnModuleAlf').val(selectedVal);
}
else {
$("#alfModules").hide();
$("#groupname-checker-alf").hide();
$("#hdnAlf").val("false");
$("#username-checker-alf").hide();
filters.alf = 0;
$('#hdnModuleAlf').val("false");
$("#txtGroupnameExistsAlf").val("").css("background-color", "white");
}
if ($('.module-selection #chkBrad').is(':checked')) {
// Show Div
$("#bradModules").show();
$("#groupname-checker-brad").show();
// Show username checker for Alf
$("#username-checker-brad").show();
// Set alf value for one to be passed to Ajax request
filters.brad = 1;
var selectedVal = $("#ddlSelectedBrad :selected").val();
$('#hdnModuleBrad').val(selectedVal);
}
else {
$("#bradModules").hide();
$("#groupname-checker-brad").hide();
$("#hdnBrad").val("false");
$("#username-checker-brad").hide();
filters.brad = 0;
$('#hdnModuleBrad').val("false");
$("#txtGroupnameExistsBrad").val("").css("background-color", "white");
}
filters.username = $('#createuser-usernamesearch #user_name').val();
return filters;
}
function searchUsername() {
var filters = chkSelection();
$.ajax({
url: '#Url.Action("UsernameSearch", "UserManager")',
type: "POST",
async: true,
dataType: "json",
data: "username=" + filters.username,
success: function (data) {
var usernameExistsAlf = parseInt(data.usernameAlf);
if (usernameExistsAlf > 0) {
$('#txtUsernameExistsAlf').val("Username already exists").css("background-color", "red");
}
else {
$('#txtUsernameExistsAlf').val("Username doesn't exist").css("background-color", "#33ff00");
}
var usernameExistsBrad = parseInt(data.usernameBrad);
if (usernameExistsBrad > 0) {
$('#txtUsernameExistsBrad').val("Username already exists").css("background-color", "red");
}
else {
$('#txtUsernameExistsBrad').val("Username doesn't exist").css("background-color", "#33ff00");
}
},
error: function (data) {
}
});
}
$("#group_name").autocomplete({
source: function (request, response) {
$.ajax({
url: '#Url.Action("LookUpGroupName", "UserManager")',
dataType: "json",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
value: request.term
},
success: function (data) {
response($.map(data, function (item) {
// alert(item.group);
return {
label: item.group,
value: item.group
} // end of return
})); // end of response
}, // end of success
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
} // end of error
}); // end of ajax
},
minLength: 2,
select: function (event, ui) { // Assign to hidden values to trigger onchange ajax call.
$.ajax({
url: '#Url.Action("GroupnameCheck", "UserManager")',
dataType: "json",
data: {
featureClass: "P",
style: "full",
maxRows: 12,
value: ui.item.label
},
success: function (data) {
$.each(data, function (index, value) {
if (index == "AlfGroup") {
$("#txtGroupnameExistsAlf").val(value);
if ($("#txtGroupnameExistsAlf").val() == "Alf Group doesn't exist.") {
$("#txtGroupnameExistsAlf").css("background-color", "red");
}
else {
$('#txtGroupnameExistsAlf').css("background-color", "#33ff00");
}
}
if (index == "BradGroup") {
$("#txtGroupnameExistsBrad").val(value);
if ($("#txtGroupnameExistsBrad").val() == "Brad Group doesn't exist.") {
$("#txtGroupnameExistsBrad").css("background-color", "red");
}
else {
$('#txtGroupnameExistsBrad').css("background-color", "#33ff00");
}
}
});
}, // end of success
error: function (jqXHR, textStatus, errorThrown) {
alert(textStatus);
} // end of error
}); // end of ajax
$('#hdnGroupAlf').val(ui.item.label);
$('#hdnGroupBrad').val(ui.item.label);
},
open: function () {
$(this).removeClass("ui-corner-all").addClass("ui-corner-top");
},
close: function () {
$(this).removeClass("ui-corner-top").addClass("ui-corner-all");
}
});
$(document).ready(function () {
chkSelection();
});
</script>
My layout with all the scripts
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>#ViewBag.Title</title>
<!-- Javascript -->
<script src="../../Scripts/jquery-1.8.3.min.js" type="text/javascript"></script>
#* <script src="#Url.Content("~/Scripts/jquery-1.5.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.autocomplete.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/Custom/autocompleteGroup.js")" type="text/javascript"></script>*#
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" />
<script src="http://code.jquery.com/jquery-1.8.3.js"></script>
<script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
<!-- Javascript -->
<!-- Stylesheets -->
<link href="#Url.Content("~/Content/themes/base/jquery.ui.autocomplete.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/themes/base/jquery.ui.autocomplete.custom.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/Site.css")" rel="stylesheet" type="text/css" />
<!-- Stylesheets -->
</head>
<body>
<div class="page">
<div id="header">
<div id="title" >
<h1>ALF and BRAD User Manager</h1>
</div>
<div id="logindisplay">
<span style="color:Black; background-color:white; text-align:right;">
Logged in as:&nbsp<strong>#Context.User.Identity.Name</strong>
</span>
</div>
<nav>
<ul id="menu">
#Html.ActionLink("User Manager Dashboard", "Index", "UserManager")&nbsp&nbsp
#Html.ActionLink("User Analytics", "Index", "UserStatus")&nbsp&nbsp
#Html.ActionLink("Email Distibution", "Index", "EmailDistributionList")&nbsp&nbsp
#Html.ActionLink("Email User Details", "Index", "EmailUserDetails")&nbsp&nbsp
</ul>
</nav>
</div>
<section id="main">
#RenderBody()
</section>
<footer>
</footer>
</div>
</body>
</html>
#* <script type="text/javascript">
$(document).ready(function () {
doAutocomplete('#Url.Action("LookUpGroupName", "UserManager")');
});
</script>*#
So any help? Thanks!
This is how it should work. You will still get to the method, but can check the ModelState to decide what to do, for example...
if (ModelState.IsValid) {
// Save, redirect to action
}
return View(model); // send them back to correct the problem!
You will also be able to display the errors on the view, as they will be present. You can use a ValidationSummary or have individual ValidationFor elements.
Check the below link. It may help you.
Client side validation
Update:
You need to enable clientside validation, unobtrusivejavascript and refer the script files in master page.
[web.config]
<appSettings>
<add key="webpages:Version" value="1.0.0.0" />
<add key="ClientValidationEnabled" value="true" />
<add key="UnobtrusiveJavaScriptEnabled" value="true" />
</appSettings>
[layout.cshtml]
<script src="#Url.Content("~/Scripts/jquery-1.5.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.unobtrusive-ajax.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.js")" type="text/javascript"></script>

Using Ajax gives stale results

EDIT
My Ajax form gets correct Id to update a content and a replace option.
Submitting is by clicking <input type="submit" value="submit!" />.
Problem: When I clicked on submit I didn't see any update. Second trial gave the expected result. When I refreshed the page the lost record (first hit was successful) was on spot.
Model
[Serializable]
public abstract class AbstractEntity {
public Guid Id { get; set; }
public DateTime LastModified { get; set; }
}
[Serializable]
public class Product : AbstractEntity {
public Product() {
this.Attachments = new HashSet<Attachment>();
}
public String Title { get; set; }
public String Commentary { get; set; }
public DateTime PlacedOn { get; set; }
public String User { get; set; }
public ICollection<Attachment> Attachments { get; set; }
}
[Serializable]
public class Attachment {
public String MimeType { get; set; }
public String Description { get; set; }
public String Filename { get; set; }
}
Controller
[HandleError]
public class ProductController : Controller {
private readonly IDocumentSession documentSession;
public ProductController(IDocumentSession documentSession) {
this.documentSession = documentSession;
}
public ActionResult ListRecent() {
return View(ListAll());
}
[Audit, HttpPost]
public ActionResult Delete(Guid id) {
documentSession.Delete<Product>(documentSession.Load<Product>(id));
documentSession.SaveChanges();
return PartialView("ProductsList", ListAll());
}
[Audit, HttpPost]
public ActionResult Create(Product product) {
if(ModelState.IsValid) {
documentSession.Store(product);
documentSession.SaveChanges();
}
return PartialView("ProductsList", ListAll());
}
private IEnumerable<Product> ListAll() {
return documentSession.Query<Product>().ToArray();
}
}
Views ('scriptless')
Layout
<head>
<title>#ViewBag.Title</title>
<link href="#Url.Content("~/Content/stylesheets/normalize.css")" rel="stylesheet" type="text/css" />
<link href="#Url.Content("~/Content/stylesheets/site.core.css")" rel="stylesheet" type="text/css" />
<script src="#Url.Content("~/Scripts/jquery-1.7.2.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.unobtrusive-ajax.js")" type="text/javascript"></script>
</head>
<body>
<div id="main-wrapper">
<div id="header">[#Html.ActionLink("List", "ListRecent", "Product")]</div>
<div id="content">#RenderBody()</div>
</div>
</body>
ListRecent.cshtml
#model IEnumerable<lamp.DomainLayer.Entities.Product>
#{
ViewBag.Title = "ListRecent";
var options = new AjaxOptions {
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "productsList"
};
}
<h2>List</h2>
#Html.Partial("ProductsList", Model)
#using(Ajax.BeginForm("Create", "Product", options)) {
<fieldset>
<p>
<label class="autoWidth">Title</label>
#Html.Editor("Title")
#Html.ValidationMessage("Title")
</p>
<p>
<label class="autoWidth">Commentary</label>
#Html.TextArea("Commentary")
#Html.ValidationMessage("Commentary")
</p>
#* Some fields I have omitted.. *#
<input type="submit" value="submit" />
<input type="reset" value="clear" />
</fieldset>
}
ProductsList.cshtml
#model IEnumerable<lamp.DomainLayer.Entities.Product>
#{
var options = new AjaxOptions {
InsertionMode = InsertionMode.Replace,
UpdateTargetId = "productsList"
};
}
<div id="productsList">
#foreach(var p in Model) {
<div class="productCard">
<p class="title"><strong>Title</strong>: #p.Title</p>
<p class="author"><strong>User</strong>: #p.User</p>
<p class="date"><strong>Placed on</strong>: #idea.PlacedOn.ToShortDateString()</p>
<p class="link">#Html.ActionLink("details", "Details", "Product")</p>
<p class="link">
#using(Ajax.BeginForm("Delete", "Product", new { id = p.Id }, options)) {
<input type="submit" value="you!" />
}
</p>
</div>
}
</div>
I guess it is IE's fault (precisely the way,how IE cache AJAX requests). Look here-it could be solution:
http://viralpatel.net/blogs/ajax-cache-problem-in-ie/
Ok. Darin was right! I found out that changing my controller code to this one:
private IEnumerable<Product> ListAll() {
return documentSession
.Query<Product>()
.Customize((x => x.WaitForNonStaleResults()))
.ToArray();
}
fixes everything.
.Customize((x => x.WaitForNonStaleResults()))
is the solution!
Thanks everyone!

html.dropdownlist MVC3 confusion

This works for me but how do I do the same thing using html.dropdownlist?
Notice that the value passed is not the value that is shown to the user.
#model IEnumerable<MVR.Models.ViewIndividual>
<h2>Level1</h2>
<select>
#foreach (var item in Model) {
<option value="#item.Case_Number">#item.Patient_Lastname ,
#item.Patient_Firstname
</option>
}
</select>
As always in an ASP.NET MVC application you start by defining a view model:
public class MyViewModel
{
public string SelectedIndividual { get; set; }
public SelectList Individuals { get; set; }
}
then you write a controller action that populates this view model from some data source or something:
public ActionResult Index()
{
// TODO : fetch those from your repository
var values = new[]
{
new { Value = "1", Text = "item 1" },
new { Value = "2", Text = "item 2" },
new { Value = "3", Text = "item 3" },
};
var model = new MyViewModel
{
Individuals = new SelectList(values, "Value", "Text")
};
return View(model);
}
and finally you have a strongly typed view using strongly typed helpers:
#model MyViewModel
#Html.DropDownListFor(
x => x.SelectedIndividual,
Model.Individuals
)
This being said, because I see that you are not using any view models in your application, you could always try the following ugliness (not recommended, do this at your own risk):
#model IEnumerable<MVR.Models.ViewIndividual>
<h2>Level1</h2>
#Html.DropDownList(
"SelectedIndividual",
new SelectList(
Model.Select(
x => new {
Value = x.Case_Number,
Text = string.Format(
"{0}, {1}",
x.Patient_Lastname,
x.Patient_Firstname
)
}
),
"Value",
"Text"
)
)
Of course such pornography is not something that I would recommend to ever write in a view and I wouldn't recommend even to my worst enemies.
Conclusion: In an ASP.NET MVC application you should always be using view models and strongly typed views with strongly typed helpers (see first part of my answer).
Here is the full example
public class PageModel
{
[Display(Name = "Page ID")]
public Guid ID { get; set; }
[Display(Name = "Page Type ID")]
public Guid PageTypeID { get; set; }
[Display(Name = "Title")]
public string Title { get; set; }
[Display(Name = "Page Type Name")]
public string PageTypeName { get; set; }
[Display(Name = "Html Content")]
public string HtmlContent { get; set; }
public SelectList PageTypeList { get; set; }
}
the C# code
public ActionResult Edit(Guid id)
{
var model = db.Pages.Where(p => p.ID == id).FirstOrDefault();
var typeList = new SelectList(db.PageTypes.OrderBy(s => s.Name).ToList(), "ID", "Name");
var viewModel = new PageModel { PageTypeList = typeList };
viewModel.HtmlContent = model.HtmlContent;
viewModel.ID = model.ID;
viewModel.PageTypeID = Guid.Parse(model.PageTypeID.ToString());
viewModel.Title = model.Title;
return View(viewModel);
}
[HttpPost]
[ValidateInput(false)]
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult Edit(PageModel page)
{
if (ModelState.IsValid)
{
var model = db.Pages.Where(p => p.ID == page.ID).FirstOrDefault();
model.Title = page.Title;
model.HtmlContent = page.HtmlContent;
model.PageTypeID = page.PageTypeID;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(page);
}
and lastly html
#model competestreet.com.Models.PageModel
#{
ViewBag.Title = "Edit";
Layout = "~/Views/Shared/_LayoutCMS.cshtml";
}
<script type="text/javascript">
$(document).ready(function () {
$('#HtmlContent').ckeditor();
});
</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>
<script src="#Url.Content("~/Scripts/ckeditor/ckeditor.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/ckeditor/adapters/jquery.js")" type="text/javascript"></script>
<h2 class="title">
<span class="text-cms">CM<span>S</span></span></h2>
<div class="box">
<div class="t">
</div>
<div class="c">
<div class="content">
<div class="main-holder">
<div id="sidebar">
<ul>
<li>Home</li>
<li>Pages</li>
</ul>
</div>
<div id="content" style="min-height: 500px;">
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Page Type - #Html.DropDownListFor(x => x.PageTypeID, Model.PageTypeList)
#Html.ValidationMessageFor(model => model.PageTypeID)</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Title)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Title, new { #class = "text-box" })
#Html.ValidationMessageFor(model => model.Title)
</div>
<div class="clear">
</div>
<div class="editor-label">
#Html.LabelFor(model => model.HtmlContent)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.HtmlContent, new { #name = "Editor1", #class = "Editor1" })
#Html.ValidationMessageFor(model => model.HtmlContent)
</div>
<div class="clear">
</div>
<p>
<input type="submit" value="Save" class="input-btn" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
</div>
</div>
</div>
</div>
<div class="b">
</div>
</div>

Resources