ValidationMessageFor for different object - asp.net-mvc

I'm using mvc4, in my view I have a declaration
#model IEnumerable<UserDisplay>
on the same view I want to have a Form with "create" post for different object type name "Review"
how can I use the EditorFor and ValidationMessageFor ? cause model is of different type.
this is not working
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Review</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Info)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Info)
#Html.ValidationMessageFor(model => model.Info)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.FromId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.FromId)
#Html.ValidationMessageFor(model => model.FromId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ToId)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ToId)
#Html.ValidationMessageFor(model => model.ToId)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}

Create a partial view for that form that uses the #model declaration of the required type then use #Html.Partial("mySubFormView"). Don't mix model types in your views, it makes life too complicated.

You can use a view model containing both objects.
public class MyViewModel
{
public IEnumerable<UserDisplay> { get; set; }
public Review Review { get; set; }
}
Then your model declaration in the view becomes:
#model TheNamespace.For.MyViewModel
Which will allow you to use #Html.EditorFor and #Html.ValidationMessageFor helpers.

Related

Remote Validation working elsewhere

I have a user registration page where I implemented the remote validation concept for the Username. I basically want to keep each Username a unique value. I was able to achieve it, but now in the login page, when I type the username it prompts a message saying the Username is not available. This was meant just for the registration page and not the login page. Could someone please explain what is the mistake I am doing. I have a Model User which has a Username property; to which I am using the remote validation. I have an Action method called UserNameExsists which gets triggered for the remote validation. And the Registration view which utilities the validation. But the validation is being triggered for the login page as well. Is there a way I could set it up just for the Registration View?
Model:
public class User
{
public int ID { get; set; }
[Required]
[Remote("UserNameExists","User",ErrorMessage="Username not available")]
[Display(Name="User Name")]
public string UserName { get; set; }
[Required]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required]
[Display(Name="First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name="Last Name")]
public string LastName { get; set; }
[Required]
[DataType(DataType.PhoneNumber)]
[MinLength(10)]
[MaxLength(10)]
[Display(Name="Mobile No")]
public string PhoneNum { get; set; }
}
Controller: (Name is User)
//Remote Validation
public JsonResult UserNameExists(string username)
{
bool user = db.Users.Any(p => p.UserName == username) ? false : true;
return Json(user,JsonRequestBehavior.AllowGet);
}
View:
Registration page view
#model HindiMovie.Models.User
#{
ViewBag.Title = "Register";
}
<link href="~/Content/Site.css" rel="stylesheet" />
<script src="~/Scripts/jquery-1.8.2.min.js"></script>
<script src="~/Scripts/jquery.validate.min.js"></script>
<script src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<h2>Register</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>User</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.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</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.PhoneNum)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNum)
#Html.ValidationMessageFor(model => model.PhoneNum)
</div>
<p>
<input type="submit" value="Register" />
<input type="reset" value="Clear" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Login page View:
#model HindiMovie.Models.User
#{
ViewBag.Title = "Login";
}
<h2>Login</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
<fieldset>
<legend>User</legend>
<div class="editor-label">
#Html.LabelFor(model => model.UserName)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.UserName)
#Html.ValidationMessageFor(model => model.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.PasswordFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<p>
<input type="submit" value="Sign in" />
</p>
</fieldset>
}
#Html.ValidationMessage("LogOnError")
<div>
#Html.ActionLink("Create account", "Register","User")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
You are using the same model for the Login and the Registration page, so you get the same validation on both pages.
Create a ViewModel for each view and put your validation attributes there.
That way you can differentiate between the validations for each page.

Cannot convert lambda expression to type 'string' because it is not a delegate type MVC

I know there is a lot of topics like this one, but I cant find the answer.
In code:
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>TabelaModel</legend>
#Html.HiddenFor(model => model.ID)
<div class="editor-label">
#Html.LabelFor(model => model.Druzyna)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Druzyna)
#Html.ValidationMessageFor(model => model.Druzyna);
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LiczbaMeczy)
</div>
<div class="editor-field">
#Html.TextBox(model => model.LiczbaMeczy)
#Html.ValidationMessageFor(model => model.LiczbaMeczy)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.LiczbaGoliStrzelonych)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.LiczbaGoliStrzelonych)
#Html.ValidationMessageFor(model => model.LiczbaGoliStrzelonych)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
Compiler is throwing an exception in line:
#Html.TextBox(model => model.LiczbaMeczy)
I have put a System.Linq, System.Data.Entity in model, in view, in controller, but still nothing. It's working when i replace #Html.TextBox into #Html.EditorFor, but i really would like to avoid this. My model class:
namespace GridViewTest.Models
{
public class TabelaModel
{
public int ID { get; set; }
public string Druzyna { get; set; }
[Required (ErrorMessage="*")]
public string LiczbaMeczy { get; set; }
[Required(ErrorMessage = "*")]
public int LiczbaGoliStrzelonych { get; set; }
}
}
Could You help me ?
You need to use TextBoxFor (not TextBox):
#Html.TextBoxFor(model => model.LiczbaMeczy)
That will take the lambda expression.

MVC Range Attribute not working properly

I have a RangeAttribute that checks if the value of a data field is within a specified range of values here, that gives me a validation error even if I pick a date in between "01/01/2000", "01/01/2015":
[Range(typeof(DateTime), "01/01/2000", "01/01/2015")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[DataType(DataType.Date)]
public Nullable<System.DateTime> Date { get; set; }
Here is my edit.cshtml code:
#model StringLength.Models.Employee
#{
ViewBag.Title = "Edit";
}
<h2>Edit</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Employee</legend>
#Html.HiddenFor(model => model.ID)
<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.Gender)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Gender)
#Html.ValidationMessageFor(model => model.Gender)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Email)
#Html.ValidationMessageFor(model => model.Email)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Age)
#Html.ValidationMessageFor(model => model.Age)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Date)
#Html.ValidationMessageFor(model => model.Date)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
For instance, if I pick 1.1.2014, I am NOT supposed to see any validation error.
Could anyone please help?
Thanks in advance!
First, DateTime structs weren't properly created from given strings. As your message in red states those strings were converted to 1.1.1910 and 1.1.2060 DateTimes. You should go with CustomValidation attribute.
Second, there might be a problem with converting 01.01.2014 to DateTime at server side. Bear in mind you might be using a specific culture that plays a role in conversions and bindings.
To fix this, we can create a custom DateRangeAttribute. Here are the steps
1. Right click on the project name in solution explorer, and add "Common" folder.
2. Right click on the "Common" folder and add a class file with name = DateRangeAttribute.cs
3. Copy and paste the following code in DateRangeAttribute.cs class file.
using System;
using System.ComponentModel.DataAnnotations;
namespace MVCDemo.Common
{
public class DateRangeAttribute : RangeAttribute
{
public DateRangeAttribute(string minimumValue)
: base(typeof(DateTime), minimumValue, DateTime.Now.ToShortDateString())
{
}
}
}
Finally decorate "HireDate" property with our custom DateRangeAttribute as shown below. Notice that, we are only passing the minimum date value. Maximum date value will be today's date. Please note, DateRangeAttribute is present in MVCDemo.Common namespace.
[DateRange("01/01/2000")]
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime HireDate { get; set; }

Saving forms in mvc

I'm completely new to MVC having made the decision to try make the switch from aspx WebForms.
I have created a view using the MVC view creator wizard and selected a strongly typed class and an edit Scaffold template.
I got the following
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Company</legend>
#Html.HiddenFor(model => model.Id)
<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.PhoneNumber)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumber)
#Html.ValidationMessageFor(model => model.PhoneNumber)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
In the Controller I have the following to get the model details
[System.Web.Http.HttpGet]
public ActionResult Edit(int id)
{
var uow = new BlogUow();
var company = uow.Companies.GetById(id);
return View(company);
}
This works fine but the problem is, I'm stumped on how I actually save the newly entered details.
I relied too much on how the web forms handle post backs.
You must write a post action for your edit in the controller:
[System.Web.Http.HttpPost]
public ActionResult Edit(Companies company)
{
var uow = new BlogUow();
if (ModelState.IsValid)
{
uow.Entry(company).State = EntityState.Modified;
return RedirectToAction("Index");
}
return View(company);
}
note Companies overload
[HttpPost]
public ActionResult Edit(Companies company)
{
var uow = new BlogUow();
if (ModelState.IsValid)
{
Edit here
}
return View(company);
}

Override Default MVC Editor Templates Not Working

I've been unable to get default editor templates to work in my MVC 4 Razor web application. I've been unable to find any clues. I want to override String, Password, etc. I've tried UIHints in my model (even though you shouldn't have to for default editor templates), ensured I'm using EditorFor in my view and have placed the Editor Templates under ~/Views/Shared/EditorTemplates. I'm stuck. Any help would be appreciated. Thanks!
public class LoginModel
{
[Required(AllowEmptyStrings = false)]
[StringLength(128)]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required(AllowEmptyStrings = false)]
[DataType(DataType.Password)]
[Display(Name = "Password")]
public string Password { get; set; }
[Display(Name = "Remember me?")]
public bool RememberMe { get; set; }
[HiddenInput()]
public Guid UserEmailAddressId { get; set; }
[HiddenInput()]
public bool IsVerified { get; set; }
}
Part of my view where I'm binding to my model...
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>RegisterModel</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.PrimaryEmailAddress)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PrimaryEmailAddress)
#Html.ValidationMessageFor(model => model.PrimaryEmailAddress)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Password)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Password)
#Html.ValidationMessageFor(model => model.Password)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ConfirmPassword)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ConfirmPassword)
#Html.ValidationMessageFor(model => model.ConfirmPassword)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.CultureId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.CultureId, (IEnumerable<SelectListItem>)ViewBag.Cultures, " -- Select -- ", null)
#Html.ValidationMessageFor(model => model.CultureId)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.TimeZoneId)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.TimeZoneId, (IEnumerable<SelectListItem>)ViewBag.TimeZones, " -- Select -- ", null)
#Html.ValidationMessageFor(model => model.TimeZoneId)
</div>
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
In the Password.cshtml file under ~/Views/Shared/EditorTemplates/Password.cshtml
#Html.Password("", ViewData.TemplateInfo.FormattedModelValue, new { #class = "k-textbox" })
THE EDITOR IS WORKING
Turns out I was looking at the wrong View. The actual View was using #Html.TextBoxFor which is why the Default Editor Template for the password was not rendering. You need to use #Html.EditorFor to invoke the default editor template.

Resources