Model Validation without checking Integer - validation

I don't want to check StudentID. I just want only StudentName validation. But when I am running the code it is showing me the validation of both properties.How can I solve this problem
public class Student
{
public int StudentID { get; set; }
[Required]
public string StudentName { get; set; }
}
Controller Code:
[HttpPost]
public ActionResult Crud(Student student)
{
if(ModelState.IsValid)
{
return RedirectToAction("Crud");
}
return View();
}
View Page Code:
#using (Ajax.BeginForm("Crud", "Students", new AjaxOptions
{ HttpMethod = "POST" }))
{
#Html.ValidationSummary()
<div>
#Html.LabelFor(x => x.StudentID)<br />
#Html.EditorFor(x => x.StudentID)
</div><br />
<div>
#Html.LabelFor(x => x.StudentName)<br />
#Html.EditorFor(x => x.StudentName)
</div><br />
<input type="submit" value="SAVE" />
}
Output:
Both validation are showing here. But I want only StudentName validation

Related

How to use CheckBoxFor in MVC forms with other form controls

Basically, i have a form with a textbox, radio button and a check box control. now i face problem with the checkbox control when i submit my page
I have a model like this
public class PersonDetails
{
public int personID { get; set; }
public string PersonName { get; set; }
public string Gender { get; set; }
public List<Education> Education { get; set; }
public string EmailID { get; set; }
public string Address { get; set; }
}
public class Education
{
public string Qualification { get; set; }
public bool Checked { get; set; }
public List<Education> GetQualification()
{
return new List<Education>{
new Education {Qualification="SSC",Checked=false},
new Education {Qualification="HSC",Checked=false},
new Education {Qualification="Graduation",Checked=false},
new Education {Qualification="PostGraduation",Checked=false}
};
}
}
and i have a view like this
#using (Html.BeginForm("GetDetails", "User", FormMethod.Post, new { id = "person-form" }))
{
<div class="col-xs-12">
<label>Person Name</label>
#Html.TextBoxFor(x => x.PersonName)
</div>
<div class="col-xs-12">
<label>Gender</label>
#Html.RadioButtonFor(x => x.Gender, "Male")
#Html.RadioButtonFor(x => x.Gender, "Female")
</div>
<div class="col-xs-12">
<label>Education</label>
#{
Html.RenderPartial("Qualification", new LearnAuthentication.Controllers.Education().GetQualification());
}
</div>
<div class="col-xs-12">
<input type="submit" value="Submit" />
</div>
}
and the partial view like this
#model List<LearnAuthentication.Controllers.Education>
<br />
#for (int i = 0; i < Model.Count(); i++)
{
#Html.HiddenFor(x => Model[i].Qualification)
#Html.CheckBoxFor(x => Model[i].Checked)
#Html.DisplayFor(x => Model[i].Qualification)
<br />
}
and my action method is this
[HttpPost]
public ActionResult GetDetails(PersonDetails personDetails)
{
return View();
}
now when i run my app i tend to get all the information but when i submit the page i get this property with null values
public List Education { get; set; }
can any of you guys help me on what i am doing wrong or could you direct me to the right path on how to achieve this.
Your use of a partial to generate the controls for Education is generating inputs such as
<input type="hidden" name="[0].Qualification" ... />
<input type="hidden" name="[1].Qualification" ... />
but in order to bind, they need to have name attributes which match your model
<input type="hidden" name="Education[0].Qualification" ... />
<input type="hidden" name="Education[1].Qualification" ... />
Rename you partial to Education.cshtml (to match the name of the class) and move it to your /Views/Shared/EditorTemplates folder (or /Views/yourControllerName/EditorTemplates if you want a specific template just for that controller)
Then change the partial to
#model LearnAuthentication.Controllers.Education
#Html.HiddenFor(m => m.Qualification)
#Html.LabelFor(m => m.Checked)
#Html.CheckBoxFor(m => m.Checked)
#Html.DisplayFor(m => m.Qualification)
and in the main view replace
<label>Education</label>
#{ Html.RenderPartial("Qualification", new LearnAuthentication.Controllers.Education().GetQualification()); }
with
<span>Education</span> // its not a label
#Html.EditorFor(m => m.Education)
which will correctly generate the correct html for each item in your collection
Side note: Other alternatives which would work would be to change the POST method signature to
[HttpPost]
public ActionResult GetDetails(PersonDetails personDetails List<Education> educationDetails)
or to pass the HtmlFieldPrefix to the partial as explained in getting the values from a nested complex object that is passed to a partial view

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

MVC3 simple custom validation

simple custom validation,
my model and custom validation:
public class Registration
{
[Required(ErrorMessage = "Date of Birth is required")]
[AgeV(18,ErrorMessage="You are not old enough to register")]
public DateTime DateOfBirth { set; get; }
}
public class AgeVAttribute : ValidationAttribute
{
private int _maxAge;
public AgeVAttribute(int maxAge)
{
_maxAge = maxAge;
}
public override bool IsValid(object value)
{
return false; <--- **this never gets executed.... what am I missing?**
}
}
(Please see the inline comment above)
view:
#using (Html.BeginForm()) {
#Html.ValidationSummary("Errors")
<fieldset>
<legend>Registration</legend>
<div class="editor-label">
#Html.LabelFor(model => model.DateOfBirth)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DateOfBirth)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Can't repro.
Model:
public class Registration
{
[Required(ErrorMessage = "Date of Birth is required")]
[AgeV(18, ErrorMessage = "You are not old enough to register")]
public DateTime DateOfBirth { set; get; }
}
public class AgeVAttribute : ValidationAttribute
{
private int _maxAge;
public AgeVAttribute(int maxAge)
{
_maxAge = maxAge;
}
public override bool IsValid(object value)
{
return false;
}
}
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new Registration
{
DateOfBirth = DateTime.Now.AddYears(-10)
});
}
[HttpPost]
public ActionResult Index(Registration model)
{
return View(model);
}
}
View:
#model Registration
#using (Html.BeginForm())
{
#Html.ValidationSummary("Errors")
<fieldset>
<legend>Registration</legend>
<div class="editor-label">
#Html.LabelFor(model => model.DateOfBirth)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DateOfBirth)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
The IsValid method is always hit when the form is submitted. Also notice that I haven't enabled client side validation because I didn't include the jquery.validate.js and the jquery.validate.unobtrusive.js scripts. If you have included them and there's an error chances are that client side validation will prevent your form from even being submitted to the server in which case it would be normal for the IsValid method not being invoked.

Date validation on search input/textbox for a razor view MVC

I would like to add a textbox (date) and button to my report, which filters the data.
The below mvc is working, but the input must still be validated (must be a DATE) on client side (and server side if possible)
My Model looks like this :
public class DailyReport
{
public int DailyReportID { get; set; }
public DateTime? ReportDate { get; set; }
}
View :
#model IEnumerable<project_name.Models.DailyReport>
#* text box and button: *#
#using (Html.BeginForm("Index", "DailyReport", FormMethod.Get))
{ <p>
Title: #Html.TextBox("SearchDateString")
<input type="submit" value="Filter" />
</p>
}
#* display dates*#
#foreach (var item in Model)
{ #Html.DisplayFor(modelItem => item.ReportDate)
}
my controller:
public ViewResult Index(String SearchDateString)
{
var dailyreport = db.DailyReport.Include(d => d.Site);
if (!String.IsNullOrEmpty(SearchDateString))
{
DateTime search_date = Convert.ToDateTime(SearchDateString);
dailyreport = dailyreport.Where(r => r.ReportDate == search_date);
}
return View(dailyreport.ToList());
}
Can someone help me please?
How do I make sure a valid date is entered in the textbox?
Should I create a another model with a date field for this input?
Utilize the DataTypeAttribute from the DataAnnotations namespace in your Model, like so:
public class DailyReport
{
public int DailyReportID { get; set; }
public DateTime? ReportDate { get; set; }
}
public class DrViewModel
{
[DataType(DataType.Date)]
public string DateTimeSearch { get; set; }
List<DailyReport> DailyReports { get; set; }
}
In your View, have something like:
#model project_name.Models.DrViewModel
#using (Html.BeginForm("Index", "DailyReport", FormMethod.Get))
{
<p>
Title: #Html.TextBoxFor(m => m.DateTimeSearch)
<input type="submit" value="Filter" />
</p>
}
#foreach (var item in Model.DailyReports)
{
#Html.DisplayFor(m => item.ReportDate)
}
#Shark Shark pointed me in the right direction to use a viewmodel, this is the end result that is now working. JS validation added as well.
(DBSet was not necessary because DrViewModel is a viewmodel.)
controllers :
public ActionResult Index(DrViewModel dvm)
{
var dailyreport = db.DailyReport.Include(d => d.Site);
if (dvm.DateTimeSearch != null)
{
dailyreport = dailyreport.Where(r => r.ReportDate == dvm.DateTimeSearch);
}
dvm.DailyReport = dailyreport.ToList();
return View(dvm);
}
models :
public class DrViewModel
{
public DateTime? DateTimeSearch { get; set; }
public List<DailyReport> DailyReport { get; set; }
}
public class DailyReport
{
public int DailyReportID { get; set; }
public DateTime? ReportDate { get; set; }
}
view :
#model myproject.Models.DrViewModel
#{
ViewBag.Title = "Index";
}
<h2>Index</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("Index","DailyReport", FormMethod.Get ))
{
#Html.ValidationSummary(true)
<div class="editor-label">
#Html.LabelFor(model => model.DateTimeSearch)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.DateTimeSearch)
#Html.ValidationMessageFor(model => model.DateTimeSearch)
<input type="submit" value="Filter" />
</div>
}
#foreach (var item in Model.DailyReport)
{
#Html.DisplayFor(modelItem => item.ReportDate)
}

Checkboxes in editor template are not bound to model in post action

I am using an editor template to display a checkbox for each role a user can be assigned to. The model is:
public class UserModel
{
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.EmailAddress)]
[Display(Name = "Email address")]
public string Email { get; set; }
[Required]
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[DataType(DataType.Password)]
[Display(Name = "Confirm password")]
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
public string ConfirmPassword { get; set; }
public IEnumerable<string> UserRoles { get; set; }
}
public class UserRoleModel
{
public IEnumerable<RoleViewModel> AllRoles { get; set; }
public UserModel user { get; set; }
public UserRoleModel()
{
this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel
{
Name = r
});
this.user = new UserModel();
}
}
public class RoleViewModel
{
public string Name { get; set; }
public bool Selected { get; set; }
}
The Controller:
public ActionResult Create()
{
return View(new UserRoleModel());
}
[HttpPost]
public ActionResult Create(UserRoleModel model)
{
if (ModelState.IsValid)
{
MembershipCreateStatus createStatus;
Membership.CreateUser(model.user.UserName, model.user.Password, model.user.Email, null, null, true, null, out createStatus);
if (createStatus == MembershipCreateStatus.Success)
{
foreach (var r in model.AllRoles)
{
if (r.Selected)
{
Roles.AddUserToRole(model.user.UserName, r.Name);
}
}
return RedirectToAction("Index", "Home");
}
else
{
ModelState.AddModelError("", ErrorCodeToString(createStatus));
}
}
return View(model);
}
The view:
#model BBmvc.Areas.Tools.Models.UserRoleModel
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>UserModel</legend>
<div class="editor-label">
#Html.LabelFor(model => model.user.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.user.UserName)
#Html.ValidationMessageFor(model => model.user.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.user.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.user.Email)
#Html.ValidationMessageFor(model => model.user.Email)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.user.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.user.Password)
#Html.ValidationMessageFor(model => model.user.Password)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.user.ConfirmPassword)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.user.ConfirmPassword)
#Html.ValidationMessageFor(model => model.user.ConfirmPassword)
</div>
<div class="editor-field">
#Html.EditorFor(x => x.AllRoles)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
and the editor template
#model BBmvc.Areas.Tools.Models.RoleViewModel
#Html.CheckBoxFor(x => x.Selected)
#Html.LabelFor(x => x.Selected, Model.Name)
#Html.HiddenFor(x => x.Name)
<br />
The problem is that no distinction is made in the post action whether any checkbox is checked or not. It seems that it is not getting bound to the model somehow.
Your issue comes from the deferred execution of LINQ queries. You need to eagerly initialize the collection:
public class UserRoleModel
{
public IEnumerable<RoleViewModel> AllRoles { get; set; }
public UserModel user { get; set; }
public UserRoleModel()
{
this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel
{
Name = r
}).ToList();
this.user = new UserModel();
}
}
Notice the .ToList() call:
this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel
{
Name = r
}).ToList();
And here's the explanation. When you write:
this.AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel
{
Name = r
});
at this moment the query is not executed. Only an expression tree is built but the actual query is executed only when something starts iterating over the collection. And what starts iterating? First it's the view. Inside the view you use an editor template for this collection:
#Html.EditorFor(x => x.AllRoles)
Since AllRoles is a collection property ASP.NET MVC will automatically iterate and render the editor template for each element of the collection. So this works to properly render the view.
Now let's see what happens when the form is POSTed. You post to the Create action and the default model binder kicks in. The constructor is called but since there is nothing to iterate over the AllRoles property this time the query is not executed. In fact it is executed later inside the action and the values are lost.
For this reason I would recommend you to avoid initializing your view models inside constructors. It would be better to do this inside the respective controller actions:
public class UserRoleModel
{
public IEnumerable<RoleViewModel> AllRoles { get; set; }
public UserModel user { get; set; }
}
and then:
public ActionResult Create()
{
var model = new UserRoleModel
{
AllRoles = Roles.GetAllRoles().Select(r => new RoleViewModel
{
Name = r
}).ToList(),
user = new UserModel()
};
return View(model);
}

Resources