Hidden field is not sent to service? - c#

I have a ASP.NET MVC 4 webpage where I use the following HTML code to generate a form for enduser :
#using (Html.BeginForm("JEdit", "Post", FormMethod.Post, new { id = "frmEditPost" }))
{
<div id="postListEditor" class="regularContainer" style="position:relative;">
#Html.ValidationSummary(false)
#Html.HiddenFor(c=> c.Id, false)
<div class="floatLeft">
#Html.LabelFor(c => c.Title, true)
#Html.TextBoxFor(c => c.Title, new { #class = "tb1", #Style = "width:400px;" })
#Html.ValidationMessageFor(model => model.Title)
</div>
<br style="clear:both;" />
<div class="floatLeft">
#Html.LabelFor(c => c.Text, true)
#Html.TextAreaFor(c => c.Text, new { #class = "tb1", #Style = "width:400px; height:200px" })
#Html.ValidationMessageFor(model => model.Text)
</div>
<div style="clear:both;"></div>
#Html.Raw(#Html.SubmitButton("Posta", "btPost", "", "", "ValidateFormAndAjaxSubmit('frmEditPost', this);"))
</div>
}
When clicking the submitbutton the following javascript will be runned :
function ValidateFormAndAjaxSubmit(formId, callingElement) {
if (IsNotDblClick(callingElement.id)) {
var _form = $("#" + formId);
var validator = _form.validate();
var anyError = false;
anyError = !_form.valid();
if (anyError) {
window.latestClick = '';
return false; // exit if any error found
}
$.post(_form.attr("action"), _form.serialize(), function (data) {
if (data.success && data.redirectUrl.length > 0) {
window.location.href = data.redirectUrl;
}
else {
var isValid = validateResponse(_form, data);
window.latestClick = '';
}
})
}
}
The problem is that the hiddenFor is never sent back but all other members are? I can see in the generated HTML that the hitten field is set like this :
<input data-val="true" data-val-number="The field Int32 must be a number." data-val-required="The Int32 field is required." id="Id" name="Id" type="hidden" value="21">
So why is this hittenField not sent back to the service?
Edit1 :
This is sent according to dev in Chrome
Request URL:http://localhost:5215/Post/JEdit
Request Headersview source
Accept:*/*
Content-Type:application/x-www-form-urlencoded
Origin:http://localhost:5215
Referer:http://localhost:5215/Post/Edit/42
User-Agent:Mozilla/5.0 (Windows NT 6.2; WOW64) AppleWebKit/537.22 (KHTML, like Gecko) Chrome/25.0.1364.172 Safari/537.22
X-Requested-With:XMLHttpRequest
Form Dataview sourceview URL encoded
Id:42
Title:testar3532
Text:testas3532
Url:http://test.se
Tags:
Edti2 :
This is how the ViewModel looks like :
public class EditPostViewModel
{
public int Id = -1;
public EditPostViewModel() { }
public EditPostViewModel(string title, string text, string url)
{
Title = title;
Text = text;
Url = url;
}
[Display(Name = "Titel"/*Description = "..."*/)]
[StringLength(100, MinimumLength = 3, ErrorMessage = "...")]
[Required(ErrorMessage="...")]
public string Title { get; set; }
[Display(Name = "Text")]
[StringLength(2500, MinimumLength = 3, ErrorMessage = "...")]
public string Text { get; set; }
[StringLength(100, MinimumLength = 3, ErrorMessage = "...")]
[Display(Name = "Länk")]
[RegularExpression(#"^(http(s)?://([\w-]+.)+[\w-]+(/[\w- ./?%&=])?)?$", ErrorMessage="...")]
public string Url { get; set; }
[Display(Name = "Tags")]
[TagAttribute(ErrorMessage="...a")]
public string Tags { get; set; }
public List<int> TagIdList { get; set; }
public string CustomError { get; set; }
}

ASP.NET MVC cannot bind to fields by default. Only properties. So change your Id member to a property.

Try doing #Html.HiddenFor(c => c.Id, new { Value = Model.Id })

Related

Browser error in unobtrusive for asp.net MVC

I am trying to use unobtrusive Jquery to validate in client side but something is wrong.
the error like the attached image :
this is my code:
*In BundleConfig.cs
bundles.Add(new ScriptBundle("~/bundles/jquery").Include(
"~/Scripts/jquery-{version}.js"));
bundles.Add(new ScriptBundle("~/bundles/jqueryval").Include(
"~/Scripts/jquery.validate*", "~/Scripts/jquery.unobtrusive*"));
*in the master page :
<script src="~/Scripts/jquery.validate.js" type="text/javascript"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.js" type="text/javascript"></script>
*In view model class :
public class EmployeeViewModel
{
public int? EmployeeId { get; set; }
[MaxLength(length: 10, ErrorMessage = "First name can't be more than 10 charechers")]
[Required(AllowEmptyStrings = false, ErrorMessage = ("First name is required!"))]
public string FirstName { get; set; }
[MaxLength(length: 10, ErrorMessage = "First name can't be more than 10 charechers")]
[Required(AllowEmptyStrings = false, ErrorMessage = ("Last Nmae is required!"))]
public string LastName { get; set; }
[MaxLength(length: 20)]
public string FullName { get; set; }
[Range(500, 1500, ErrorMessage = "Salare must be between 500 DK and 1500 DK")]
[Required(AllowEmptyStrings = false, ErrorMessage = ("Salary is required!"))]
public double Salary { get; set; }
[EmailAddress(ErrorMessage = "Invalid Email")]
[Required(AllowEmptyStrings =false,ErrorMessage =("Email is required!"))]
public string Email { get; set; }
public bool IsMarriage { get; set; } = false;
public string Gender { get; set; }
public string DepartmentName { get; set; }
[Required(AllowEmptyStrings = false,ErrorMessage ="Birth day is required")]
//[DataType(DataType.Date)]
public DateTime? BirthDate { get; set; }
public TimeSpan? StartWorkingTime { get; set; }
public TimeSpan? EndWorkingTime { get; set; }
public int? DepartmentId { get; set; }
}
*In view :
#using (Html.BeginForm("Save","Employee",FormMethod.Post))
{
<div class="form-group ">
<div class="row">
<div class="col-md-2 col-form-label">
#Html.LabelFor(e => e.FirstName, "First Name")
</div>
<div class="col-md-10">
#Html.TextBoxFor(e => Model.FirstName, new { #class = "form-control" })
#Html.ValidationMessageFor(e => e.FirstName, "", new { #class = "text-danger text-left" })
</div>
</div>
</div>
<div class="form-group">
<div class="row">
<div class="col-md-2">
#Html.LabelFor(e => e.LastName, "Last Name")
</div>
<div class="col-md-10">
#Html.TextBoxFor(e => Model.LastName, new { #class = "form-control" })
#Html.ValidationMessageFor(e => e.LastName, "", new { #class = "text-danger text-left" })
</div>
</div>
</div>
}
**the problem that the client validation not working, but the server side working good
I think there could be a problem with your MaxLength attribute syntax. It shoud be
[MaxLength(10, ErrorMessage = "First name can't be more than 10 charechers.")]
But for client validation, instead of using MaxLength attribute, you should try to replace it by StringLength attribute.
[StringLength(10, ErrorMessage = "First name can't be more than 10
charechers.")] [Required(AllowEmptyStrings = false, ErrorMessage =
("First name is required!"))]
public string FirstName { get; set; }
I understand this is an year old question however might help someone who might come here looking for answer.
First of all, questioner has not posted the code completely, so it is difficult to arrive at a conclusion why exactly we get error(what is undefined). I do not see the jquery client side validation rules which define the rules and messages for form inputs.
Apart from what he has done, he will need to have client side validation rules as follows:
This example is for a simple registration form which consists are Email, Password and Confirm Password as text input.The code is as follows:
$('#registerFormId').validate({
errorClass: 'help-block animation-slideDown',
// You can change the animation class for a different entrance animation - check
animations page
errorElement: 'div',
errorPlacement: function (error, e) {
e.parents('.form-group > div').append(error);
},
highlight: function (e) {
$(e).closest('.form-group').removeClass('has-success has-error').addClass('has-error');
$(e).closest('.help-block').remove();
},
success: function (e) {
e.closest('.form-group').removeClass('has-success has-error');
e.closest('.help-block').remove();
},
rules: {
'Email': {
required: true,
email: true
},
'Password': {
required: true,
minlength: 6
},
'ConfirmPassword': {
required: true,
equalTo: '#Password'
}
},
messages: {
'Email': 'Please enter valid email address',
'Password': {
required: 'Please provide a password',
minlength: 'Your password must be at least 6 characters long'
},
'ConfirmPassword': {
required: 'Please provide a password',
minlength: 'Your password must be at least 6 characters long',
equalTo: 'Please enter the same password as above'
}
}
});
Please make sure the names of your text inputs should be same as the properties that you want to validate.
Apart from this make sure Client side validation unobtrusive is enabled in web.config as follows:
Here is an excellent blog post which explains how to implement client and server side validation using jquery unobstrusive validation.
https://www.c-sharpcorner.com/article/asp-net-mvc5-jquery-form-validator/#:~:text=Server%20side%20form%20validation%2C%20as,with%20ASP.NET%20MVC5%20platform.
Asma Shaikh
Note : Above blog post is NOT written by me

MVC post action ViewModel is returned as NULL

I am trying to post the form values back to the controller. But in the action, I get the ViewModel as null.
Here is ViewModel
public class CommunicationDetailsViewModel
{
public string OrganizationName { get; set; }
public List<Country> Country { get; set; }
public List<State> State { get; set; }
public List<City> City { get; set; }
[Display(Name = "Id")]
public int CountryId { get; set; }
[Display(Name = "Id")]
public int StateId { get; set; }
[Display(Name = "Id")]
public int CityId { get; set; }
[StringLength(32), Required(ErrorMessage ="Address is required")]
public string Address { get; set; }
[StringLength(32), Required(ErrorMessage = "Building name is required")]
public string BuildingName { get; set; }
}
Below is the controller action:
[HttpPost]
public ActionResult Save(CommunicationDetailsViewModel communicationDetailsViewModel)
{
return View();
}
Does it have to do anything with the Kendo UI for MVC? Because this is the very first time I am using Kendo UI. Below is the view:
#model WebAPI.ViewModels.CommunicationDetailsViewModel
#{
ViewBag.Title = "Supplier Information";
}
<h4>Supplier Details</h4>
#using (Html.BeginForm("Save", "SupplierInformation", FormMethod.Post ))
{
<div class="demo-section k-content">
<div class="form-group">
#Html.Label("Organization name")
#Html.Kendo().TextBoxFor(model => model.OrganizationName).Name("txtOrganization").HtmlAttributes(new { #class = "k-textbox required", placeholder = "Organization Name" })
</div>
<div class="form-group">
#Html.Label("Country")
#(Html.Kendo().DropDownList().Name("ddlCountry").DataTextField("CountryName").DataValueField("Id").BindTo(Model.Country))
</div>
<div class="form-group">
#Html.Label("State")
#(Html.Kendo().DropDownList().Name("ddlState").DataTextField("StateName").DataValueField("Id").BindTo(Model.State))
</div>
<div class="form-group">
#Html.Label("City")
#(Html.Kendo().DropDownList().Name("ddlCity").DataTextField("CityName").DataValueField("Id").BindTo(Model.City))
</div>
<div class="form-group">
#Html.Label("Address")
#Html.Kendo().TextBoxFor(model => model.Address).Name("txtAddress").HtmlAttributes(new { #class="k-textbox required", placeholder="Address", #maxlength = "32" })
</div>
<div class="form-group">
#Html.Label("Building name")
#Html.Kendo().TextBoxFor(model => Model.BuildingName).Name("txtBuildingName").HtmlAttributes(new { #class = "k-textbox required", placeholder = "Address", #maxlength = "32" })
</div>
</div>
#Html.Kendo().Button().Name("btnSave").Content("Save").HtmlAttributes(new { type = "submit", #class = "k-button k-primary" })
}
And interestingly, if I use FormCollection instead of my ViewModel, I am able to get the values in the action.
What am I missing here? Must be something stupid. Any help appreciated.
I think problem here is caused by you change name by Name function. Note that MVC binding properties by name attribute of input tag so don't change it
For example you use
#Html.Kendo().TextBoxFor(model => model.OrganizationName).Name("txtOrganization").HtmlAttributes(new { #class = "k-textbox required", placeholder = "Organization Name" })
You change name of input from OrganizationName to txtOrganization that may cause MVC cann't binding properties exactly. You should keep its original name or ignore change its name like this
#Html.Kendo().TextBoxFor(model => model.OrganizationName).Name("OrganizationName").HtmlAttributes(new { #class = "k-textbox required", placeholder = "Organization Name" })

Cascading drop down won't populate

I am very new to MVC5 and JQuery and I trying to create a cascading drop down. When the user selects a Practice from the drop down I am trying to get the Opticians that work in that Practice to populate.
Optician Model:
public class Optician
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public Guid OpticianId { get; set; }
[ForeignKey("User")]
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public IEnumerable<SelectListItem> UserList { get; set; }
[ForeignKey("Practice")]
public Guid PracticeId { get; set; }
public virtual Practice Practice { get; set; }
public IEnumerable<SelectListItem> PracticeList { get; set; }
public virtual ICollection<ApplicationUser> Users { get; set; }
public virtual ICollection<Practice> Practices { get; set; }
}
Practice Model:
public class Practice
{
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
[Display(Name = "Practice")]
public Guid PracticeId { get; set; }
[Display(Name = "Practice Name")]
public string PracticeName { get; set; }
public virtual ICollection<Optician> Opticians { get; set; }
public virtual ICollection<Booking> Bookings { get; set; }
}
Application User Model:
public class ApplicationUser : IdentityUser
{
[Display(Name = "Title")]
public string Title { get; set; }
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
public string LastName { get; set; }
}
Controller :
public ActionResult TestDropDown()
{
var PracticeListItems = (from d in db.Practices
select d.PracticeName).ToList();
SelectList Practice = new SelectList(PracticeListItems);
ViewData["Practice"] = Practice;
return View();
}
public JsonResult Opticians(Guid? Id)
{
var OpticianList = (from d in db.Opticans
where d.PracticeId == Id
select d.User.FirstName).ToList();
return Json(OpticianList);
}
The View:
<script src="~/Scripts/jquery-1.10.2.js"></script>
<script>
$(document).ready(function () {
$("#Optician").prop("disabled", true);
$("#Practice").change(function () {
if ($("#Practice").val() != "Select") {
var PracticeOptions = {};
PracticeOptions.url = "/Bookings1/Opticians";
PracticeOptions.type = "POST";
PracticeOptions.data = JSON.stringify({ Practice: $("#Practice").val() });
PracticeOptions.datatype = "json";
PracticeOptions.contentType = "application/json";
PracticeOptions.success = function (OpticianList) {
$("#Optician").empty();
for (var i = 0; i < OpticianList.length; i++) {
$("#Optician").append("<option>" + StatesList[i] + "</option>");
}
$("#Optician").prop("disabled", false);
};
PracticeOptions.error = function () { alert("Error in getting Practices"); };
$.ajax(PracticeOptions);
}
else {
$("#Optician").empty();
$("#Optician").prop("disabled", true);
}
});
});
#using (Html.BeginForm("TestDropDown", "Bookings1", FormMethod.Post))
{
#Html.AntiForgeryToken()
<h4>Select Practcie & Opticians</h4>
<hr />
#Html.ValidationSummary()
<div class="form-group">
#Html.Label("Select Practice :", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.DropDownList("Practice", ViewData["Practices"] as SelectList, new { #class = "form-control" })
</div>
</div><br />
<div class="form-group">
#Html.Label("Select Optician :", new { #class = "col-md-2 control-label" })
<div class="col-md-10">
<select id="Optician"></select>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}
However, when I run the application the Practice Name populates but the Optician First Name does not. There are no errors and I am unsure of where I am going wrong. Any help would be greatly appreciated.
Seems like you have a few issues with your code.. Starting with your SelectList.
When you define your select list it helps if you tell it what your Value and Text properties are..
public ActionResult TestDropDown()
{
var practices = new SelectList(db.Practices, "PracticeId", "PracticeName");
ViewData["Practices"] = practices;
return View();
}
Then you should probably return more information in your Opticians json result
[HttpPost]
public JsonResult Opticians(Guid? Id)
{
var opticianList = db.Opticians.Where(a => a.PracticeId == Id).Select(a => a.User).ToList();
return Json(opticianList);
}
In your javascript once you get the names sorted out out you can reference the property FirstName of the result.
$(document).ready(function () {
$("#Optician").prop("disabled", true);
$("#Practice").change(function () {
$.ajax({
url = "#Url.Action("Opticians","Bookings1")",
type = "POST",
data = {Id : $(this).val() }
}).done(function(OpticianList){
$("#Optician").empty();
for (var i = 0; i < OpticianList.length; i++) {
$("#Optician").append("<option>" + OpticianList[i].FirstName + "</option>");
}
$("#Optician").prop("disabled", false);
});
});
});
I'm not sure why you were passing paramater Practice to an action that took a parameter Id but it should be fixed in the code above.

View not showing ValidationSummary and ValidationMessages

I have a View:
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<div class="input-group">
<div class="input-group-addon">
#Html.Label("Employee number", new { #class = "control-label" })
</div>
<div class="a">
#Html.TextBoxFor(model => model.EmployeeNo, new {#class="form-control" })
#Html.ValidationMessageFor(model => model.EmployeeNo)
</div>
</div>
/*
* other fields
*/
}
and Controller:
[HttpPost]
public ActionResult Edit([Bind(Include="Id,EmployeeNo,Name,Surname,ContactInfo,RoleId")] User user)
{
ValidateRequestHeader(Request);
if (ModelState.IsValid)
{
unitOfWork.userRepository.Update(user);
unitOfWork.Save();
return Json(new { ok = true, newurl = Url.Action("Index") });
}
//ModelState.AddModelError("", "Niepoprawne dane");
ViewBag.RoleId = new SelectList(unitOfWork.roleRepository.Get(), "Id", "RoleName", user.RoleId);
return PartialView(user);
}
and model:
public partial class User
{
public User()
{
this.DeviceUsages = new HashSet<DeviceUsage>();
}
public int Id { get; set; }
[Required(ErrorMessage="Brak numeru pracownika")]
public string EmployeeNo { get; set; }
[Required(ErrorMessage = "Brak imienia")]
public string Name { get; set; }
[Required(ErrorMessage = "Brak nazwiska")]
public string Surname { get; set; }
[Required(ErrorMessage = "Brak Adresu email")]
public string ContactInfo { get; set; }
public int RoleId { get; set; }
}
Data annotations are working. If I leave eg. Name empty ModelState is not Valid in controler. But validation messages are not shown. If I uncomment this line:
ModelState.AddModelError("", "Niepoprawne dane"); this will be the only Model error shown in the View.
Where is a mistake in my code?
It's because you are using #Html.ValidationSummary(true) means excludePropertyErrors = true

Using jQuery to populate a DropDownListFor

I would like to know if it is even possible to combine jQuery with a #Html.DropDownListFor in a strongly typed view, as I am beginning to suspect that either it isn't, or my approach to this problem is flawed.
Model:
public class NewUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string ConfirmEmail { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public SelectListItem DOBDay { get; set; }
public SelectListItem DOBMonth { get; set; }
public SelectListItem DOBYear { get; set; }
public string Gender { get; set; }
}
View:
#model test.Models.NewUser
#using (Ajax.BeginForm("RegisterUser", "Register", new AjaxOptions { OnSuccess = "" }))
{
<div>
#Html.TextBoxFor(m => Model.FirstName, new { #class = "big_i", #watermark = "First name" })
#Html.TextBoxFor(m => Model.LastName, new { #class = "big_i", #watermark = "Last name" })
</div>
<div>
#Html.TextBoxFor(m => Model.EmailAddress, new { #class = "big_i long_i", #watermark = "E-mail address" })
</div>
<div>
#Html.TextBoxFor(m => Model.ConfirmEmail, new { #class = "big_i long_i", #watermark = "Confirm e-mail address" })
</div>
<div>
#Html.PasswordFor(m => Model.Password, new { #class = "big_i long_i", #watermark = "Password" })
</div>
<div>
#Html.PasswordFor(m => Model.ConfirmPassword, new { #class = "big_i long_i", #watermark = "Confirm password" })
</div>
<div>
<fieldset>
<h2>
Date of birth</h2>
<div id="reg_date_control" class="date_control">
#Html.DropDownListFor(m => Model.DOBDay, Enumerable.Empty<SelectListItem>(), "Day: ", new { #class = "dc-days big_i" })
#Html.DropDownListFor(m => Model.DOBMonth, Enumerable.Empty<SelectListItem>(), "Month: ", new { #class = "dc-months big_i" })
#Html.DropDownListFor(m => Model.DOBYear, Enumerable.Empty<SelectListItem>(), "Year: ", new { #class = "dc-years big_i" })
</div>
</fieldset>
</div>
}
Controller action for form submit:
[HttpPost]
public ActionResult RegisterUser(Models.NewUser model)
{
string firstName = model.FirstName;
string lastName = model.LastName;
string email = model.EmailAddress;
string confirm_email = model.ConfirmEmail;
string password = model.Password;
string confirm_password = model.ConfirmPassword;
string dob_month = model.DOBMonth.Value; // an error is raised here
return View();
}
I am trying to initially bind the #Html.DropDownListFor with an empty list, which the jQuery will then populate. I won't paste the jQuery code here, it is basically populating each DOB drop down with the valid number of days in a selected month.
The lists populate fine. However, DOBDay, DOBMonth, and DOBYear are always null. I expect that using Enumerable.Empty() is my problem, but having said that, I have tried populating the dropdowns like so:
#model gs_mvc.Models.NewUser
#{
string[] months = new[]{"January", "February", "March", "April", "etc"};
var items = new List<SelectListItem>();
for (int i = 0; i < months.Length; i++) {
items.Add(new SelectListItem { Value = i.ToString(), Text = months[i] });
}
}
...
#Html.DropDownListFor(m => Model.DOBMonth, items, "Month: ", new { #class = "big_i" })
which also gives a null value.
At this point, I believe that my best bet would be to move the functionality of my jQuery script to C#, and do an AJAX call each time the dropdowns are changed. However, I wanted to check here first that I'm not missing something blindingly obvious that would allow me to do what I'm trying.
I think your problem is that the values on the model for month, day, and year should probably be int not SelectListItem. SelectListItem is used to build the options, since it has both the Text and Value properties, but what you want to and will receive back are just the values - not Text/Value pairs. Of course, you probably want to make them nullable so that you're sure that you're receiving values from the POST rather than just having them default to zero.
public class NewUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public string ConfirmEmail { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
public int? DOBDay { get; set; }
public int? DOBMonth { get; set; }
public int? DOBYear { get; set; }
public string Gender { get; set; }
}

Categories