I have a modal popup dialog box that loads a form to be submitted to the database. the form works fine if all the fields are filled out. If i leave blank fields and click the Create button the validation should kick in but it does not. I get the following error:
Validation failed for one or more entities. See 'EntityValidationErrors' property for more details.
Now I know what the error is. The values in the fields are null and they cannot be null to submit to the database. Also ModelState is false as well.
this is my model:
using System.ComponentModel.DataAnnotations;
using MVC_CSAlerts.Models;
namespace MVC_CSAlerts.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel;
public partial class csAlert
{
public int AlertID { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Must Enter a Route")]
public string Routes { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Must Enter an Issue")]
public string Issue { get; set; }
public string Detour { get; set; }
[DisplayName("Date")]
[DataType(DataType.DateTime)]
[Required]
public Nullable<System.DateTime> DateEntered { get; set; }
[Required]
[DisplayName("Entered By")]
public string EnteredBy { get; set; }
public Nullable<int> Count { get; set; }
[DisplayName("Send Email")]
public string SendEmail { get; set; }
[DisplayName("Is this a child alert")]
public string IsChildAlert { get; set; }
}
}
this is my view
#model MVC_CSAlerts.Models.csAlert
#{
ViewBag.Title = "Create";
}
<h2>Create New Alert</h2>
<script type="text/javascript">
$(document).ready(function () {
// We will test DataPicker
$('#DateEntered').datepicker();
// We will test tabs
$(function () {
$(document).tooltip();
});
});
</script>
#using (Ajax.BeginForm("Create","Alerts",new AjaxOptions()))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>New Alert</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Routes)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Routes)
#Html.ValidationMessageFor(model => model.Routes)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Issue)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Issue)
#Html.ValidationMessageFor(model => model.Issue)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Detour)
</div>
<div class="editor-field">
#Html.TextAreaFor(model => model.Detour)
#Html.ValidationMessageFor(model => model.Detour)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.DateEntered)
#Html.ValidationMessageFor(Model => Model.DateEntered)
</div>
<div class="editor-field">
#Html.JQueryUI().DatepickerFor(model => model.DateEntered)
#Html.ValidationMessageFor(model => model.DateEntered)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Count)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Count)
#Html.ValidationMessageFor(model => model.Count)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.SendEmail)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.SendEmail, new
SelectList(new List<object>{
new{ value = "Y", text="Yes"},
new{ value = "N",text="No"}
},
"value",
"text",
"Y"))
#* #Html.EditorFor(model => model.SendEmail)*#
#Html.ValidationMessageFor(model => model.SendEmail)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.IsChildAlert)
</div> <div class="editor-field> #Html.DropDownListFor(model =>
model.IsChildAlert, new SelectList(new List<object>{
new{ value = "Y", text="Yes"},
new{ value = "N",text="No"}
},
"value",
"text",
"Y"))
#* #Html.EditorFor(model => model.IsChildAlert)*#
#Html.ValidationMessageFor(model => model.IsChildAlert)
</div>
<p>
<input type="submit" value="Create New Alert" />
</p>
</fieldset>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
How do I get the clientside validation to load? do I have to do javascript validation in the modal window?
thanks
Try moving your: #Scripts.Render("~/bundles/jqueryval") to the Parent View instead of having it in the Modal View.
Related
I have a form with several fields and am using the standard EditorFor template to edit each value. When I display in Safari and IE then the value for "Code" appears. If I show the same form in Chrome, the value for "Code" is not visible. If i do a ViewSource then I can see the correct value, just doesn't render on page. Any ideas?
public class PageViewModel
{
public int Id { get; set; }
public string Forename { get; set; }
public string Surname { get; set; }
[Display(Name = "Code")]
[RegularExpression("^[0-9]*", ErrorMessage = "Enter digits only for the code number")]
public string Code { get; set; }
}
And my Razor is:
<div class="form-group">
#Html.LabelFor(model => model.Code, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Code)
#Html.ValidationMessageFor(model => model.Code)
</div>
</div>
Update:
If I add the "Code" field in for a second time, then the second copy correctly shows the value. So confused:
<div class="form-group">
#Html.LabelFor(model => model.Code, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Code)
#Html.EditorFor(model => model.Code)
#Html.ValidationMessageFor(model => model.Code)
</div>
</div>
This is the View-Source:
<input data-val="true" data-val-regex="Enter digits only for the code number" data-val-regex-pattern="^[0-9]*" id="Code" name="Code" type="text" value="22222">
I'm new to ASP.NET MVC 4 and I'm struggling with a concept that would be easy in webforms. So, if I have a Customer class, and a Customer has an Address, how can I edit both the Customer and Address on the same form in the same submit action? I would like to create an '_Edit' partial view for the Address, but I don't know how to wire the controller up if there is no submit button for the Address. I just want a single button to save all the Models in a single View.
So, I could create a new CompanyView model, view, and controller and do it that way. However, if I have many objects having Addresses it seems like a lot of work to keep creating View Models to allow you to edit both the object and the address in the same form. Is there a way to create an Address partial edit view and somehow update the Address fields in the Company Edit Controller? Or, have it somehow pass the model.Address back to the Company Edit Controller instead of null?
Edit:
Models
public class Address
{
public Int32 Id { get; set; }
[Display(Name = "Address 1")]
public String Address1 { get; set; }
[Display(Name = "Address 2")]
public String Address2 { get; set; }
[Display(Name = "City")]
public String City { get; set; }
[Display(Name = "State")]
public String State { get; set; }
[Display(Name = "Postal Code")]
public String PostalCode { get; set; }
[Display(Name = "Country")]
public String Country { get; set; }
}
public class Company
{
public Int32 Id { get; set; }
[Display(Name = "Company Name")]
public String Name { get; set; }
public Int32 AddressId { get; set; }
public virtual Address Address { get; set; }
}
Address _Edit Partial View
#model Models.Address
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.EditorFor(model => model.Address1)
#Html.EditorFor(model => model.Address2)
#Html.EditorFor(model => model.City)
#Html.EditorFor(model => model.State)
#Html.EditorFor(model => model.PostalCode)
#Html.EditorFor(model => model.Country)
</fieldset>
</div>
Company Edit View
#model Models.Company
#{
ViewBag.Title = "Edit";
Layout = "~/Views/shared/ContentLayout.cshtml";
}
<div class="row">
<div class="col-lg-12">
<div class="page-header">
<h2>Edit Company</h2>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
#using (Html.BeginForm("Edit", "Company", new { #class = "bs-example form-horizontal" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.EditorFor(model => model.Name)
#Html.HiddenFor(model => model.AddressId)
#Html.Partial("~/Views/Address/_Edit.cshtml", Model.Address)
<p>
<button name="button" type="submit" class="btn btn-primary" value="submit">Submit</button>
</p>
}
</div>
</div>
Company Edit Controller
[HttpPost]
public ActionResult Edit(Company model, int id)
{
if (ModelState.IsValid)
{
// model.Address = NULL here!
Success("Record updated!");
return RedirectToAction("Index");
}
}
For model binding to work properly, you need to post only a Company back to your controller. Just pass your whole model onto your partial :
#model Models.Company
#{
ViewBag.Title = "Edit";
Layout = "~/Views/shared/ContentLayout.cshtml";
}
<div class="row">
<div class="col-lg-12">
<div class="page-header">
<h2>Edit Company</h2>
</div>
</div>
</div>
<div class="row">
<div class="col-lg-8">
#using (Html.BeginForm("Edit", "Company", new { #class = "bs-example form-horizontal" })) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.EditorFor(model => model.Name)
#Html.HiddenFor(model => model.AddressId)
#Html.Partial("~/Views/Address/_Edit.cshtml", Model)
<p>
<button name="button" type="submit" class="btn btn-primary" value="submit">Submit</button>
</p>
}
</div>
</div>
_Edit
#model Models.Company
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.HiddenFor(model => model.Address.Id)
#Html.EditorFor(model => model.Address.Address1)
#Html.EditorFor(model => model.Address.Address2)
#Html.EditorFor(model => model.Address.City)
#Html.EditorFor(model => model.Address.State)
#Html.EditorFor(model => model.Address.PostalCode)
#Html.EditorFor(model => model.Address.Country)
</fieldset>
</div>
Controller
[HttpPost]
public ActionResult Edit(Company model, int id)
{
if (ModelState.IsValid)
{
// model.Address should now be available
Success("Record updated!");
return RedirectToAction("Index");
}
}
You should now see the Address navigation property of your model properly bound on post.
Edit based on question in comment
How you set up your views and partials is up to you really. The important thing to remember is that model binding works based on the names given to the form elements by the HTML helpers.
So Html.HiddenFor(m => m.Id) will result in <input name="Id"> while Html.HiddenFor(m => m.Address.Id) will result in <input name="Address.Id">. First one won't be picked up by the model binder as a navigation property of Company, second one will.
The simple route would be to just duplicate your partial view. But if it gets to the point where your partial becomes quite large and complex with a high amount of fields, you could create a partial base class that both your entities inherit of.
BaseEntityWithAddress.cs
public partial class BaseEntityWithAddress
{
public virtual Address Address { get; set; }
}
Customer.cs
public class Customer : BaseEntityWithAddress
{
// your properties, no need to redefine Address here
}
Vendor.cs
public class Vendor: BaseEntityWithAddress
{
// your properties, no need to redefine Address here
}
And then your partial view would take BaseEntityWithAddress as a model to which you would still pass the whole model.
_Edit.cshtml
#model Models.BaseEntityWithAddress
<div class="well">
<fieldset>
<legend>Address</legend>
#Html.HiddenFor(model => model.Address.Id)
#Html.EditorFor(model => model.Address.Address1)
#Html.EditorFor(model => model.Address.Address2)
#Html.EditorFor(model => model.Address.City)
#Html.EditorFor(model => model.Address.State)
#Html.EditorFor(model => model.Address.PostalCode)
#Html.EditorFor(model => model.Address.Country)
</fieldset>
</div>
And that will generate form elements with the correct names for the model binder to pick up.
So you would have 2 classes:
class Address
{
public string street {get;set;}
public string state {get;set;}
}
class Customer
{
public string name {get;set;}
public Address address {get;set;} // links to the above class.
}
your main customer view would be something like:
#model Models.Customer
#using (Html.BeginForm()
{
#Html.TextBoxFor(m => m.name)
#Html.Partial("_Edit", Model.address)
<button type="submit">Submit</button>
}
your partial:
#model Models.Address
#Html.TextBoxFor(m => m.street)
#Html.TextBoxFor(m => m.state)
then in your controller:
public ActionResult customer(Customer model)
{
// do whatever
}
My model is simple, one client can have many phone numbers :
I have represented this in Entity Framework
Generated client class is as below.
public partial class Client
{
public Client()
{
this.PhoneNumbers = new HashSet<PhoneNumber>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<PhoneNumber> PhoneNumbers { get; set; }
}
And now I need to create a view page for "create client". This page should have space to enter PhoneNumbers also (ex: By default there should be two text boxes to enter phone numbers)
<fieldset>
<legend>Client</legend>
<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>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
as the above "create view" we can easily give an space for "model.Name", because it is a simple property. But how can i do something similar for collection of phone numbers..??
I know that we can achieve this with ugly javascript code, but I would like to know the best easy and simple way, that we can use with ASP.NET MVC ... ?
You have to do a few things:
First create a ViewModel that has the properties you need:
public class ClientViewModel
{
public int Id {get;set;}
public string Name {get;set;}
public PhoneNumber PhoneNumber1 {get;set;}
public PhoneNumber PhoneNumber2 {get;set;}
}
Change Create to return the ClientViewModel
[HttpGet]
public ActionResult Create()
{
return View(new ClientViewModel());
}
Map the HttpPost to use the ClientViewModel and map the values to it:
[HttpPost]
public ActionResult Create(ClientViewModel clientViewModel)
{
var client = new Client();
client.Name = clientViewModel.Name;
client.PhoneNumbers.Add(clientViewModel.PhoneNumber1);
client.PhoneNumbers.Add(clientViewModel.PhoneNumber2);
db.Clients.Add(client);
db.SaveChanges();
return RedirectToAction("Index", "Client");
}
Then, finally, modify your view:
<fieldset>
<legend>Client</legend>
<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.PhoneNumber1.Number)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumber1.Number)
#Html.ValidationMessageFor(model => model.PhoneNumber1.Number)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PhoneNumber2.Number)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumber2.Number)
#Html.ValidationMessageFor(model => model.PhoneNumber2.Number)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
For the collection you can use something like this:
#for(int i = 0; i < Model.PhoneNumbers.Count; i++)
{
<div class="editor-field">
#Html.EditorFor(model => model.PhoneNumbers[i])
#Html.ValidationMessageFor(model => model.PhoneNumbers[i])
</div>
}
I have the following partial view called _Categories residing in ~/Views/Category/_Categories:
#model IEnumerable<MyBlogSite.Models.BlogPostCategory>
<ul>
#foreach (var item in Model)
{
<li>#Html.DisplayFor(modelItem => item.Name)</li>
}
</ul>
I have the following Index view at ~/Views/Blog/Index.cshtml:
#model IEnumerable<MyBlogSite.Models.BlogPost>
#{
ViewBag.Title = "Index";
}
#Html.RenderPartial("~/Views/Category/_Categories.cshtml", ---- );
<p>
#Html.ActionLink("New Blog Post", "Create")
</p>
<table>
<tr>
<th>
#Html.DisplayNameFor(model => model.Title)
</th>
...
In the space of the dashes (----) above is where I have been trying to figure out how to pass the model in. I cannot use Model.BlogPostCategory because it only accepts Model.BlogPost. I have also tried "model" with a lower-case "m" as per a couple of posts that I saw here.
I create viewmodel for my partialview, then pass its data. For example:
my viewmodel
public class CompanyCreateViewModel
{
public Company Company { get; set; }
public IList<CompanyContact> CompanyContacts { get; set; }
public IQueryable<ContactType> ContactTypes { get; set; }
}
partialview
#model Invoice.Model.HelperClasses.CompanyCreateViewModel
---
<div class="editor-field">
#Html.TextBoxFor(model => model.Company.FullName)
#Html.ValidationMessageFor(model => model.Company.FullName)
#Html.TextBoxFor(model => model.Company.ShortName)
#Html.ValidationMessageFor(model => model.Company.ShortName)
#Html.TextBoxFor(model => model.Company.TIN)
#Html.ValidationMessageFor(model => model.Company.TIN)
</div>
<div class="editor-field">
#Html.TextBoxFor(model => model.Company.Address.Country)
#Html.TextBoxFor(model => model.Company.Address.City)
#Html.TextBoxFor(model => model.Company.Address.Street)
</div>
---
and View with calling partialview
#model Invoice.Model.HelperClasses.CompanyViewModel
---
<div id="CompanyCreateModal" class="modal hide fade">
#{Html.RenderPartial("CompanyParts/CompanyCreateModal", new Invoice.Model.HelperClasses.CompanyCreateViewModel() { ContactTypes = Model.ContactTypes });
}
</div>
----
I am working on a tool so i can keep things organized in a game.
This is my class:
//The item
public class Item
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Value { get; set; }
public ItemLabel Label { get; set; }
public ItemType Type { get; set; }
public ItemTradeType TradeType { get; set; }
public Trade Trade { get; set; }
}
The Label / Type / TradeType / Trade are enums.
View:
#model EveMonitorV2.Models.Item
#{
ViewBag.Title = "AddItem";
}
<h2>AddItem</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Item</legend>
<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.Value)
</div>
//What should be done here?
<div class="editor-field">
#Html.EditorFor(model => model.Value)
#Html.ValidationMessageFor(model => model.Value)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Trade)
</div>
<div class="editor-field">
#Html.CheckBoxFor()
#Html.ValidationMessageFor(model => model.Trade)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
The enum has a whole list of possibilities and I want to make an Item Create view
The problem i run into:
I want to be able to select more options from the enums. (Like this)
Where the categories are my enums.
Is this possible at all in asp.net mvc 4?
(little note: I am still a student, but it isn't a school project)
Create View\Shared\EditorTemplates\Options.cshtml
#using System.ComponentModel.DataAnnotations
#using System.Reflection
#model Enum
#{
var name = ViewData.TemplateInfo.HtmlFieldPrefix;
var type = Model.GetType();
}
#foreach (Enum e in Enum.GetValues(type))
{
var display = type.GetField(e.ToString()).GetCustomAttribute<DisplayAttribute>();
if (display != null && (display.GetAutoGenerateField() ?? true))
{
<label class="checkbox" title="#display.GetDescription()">
<input type="checkbox" name="#name" value="#e.ToString()" checked="#Model.HasFlag(e)" />
#display.Name
</label>
}
}
your enum may be described as next:
[Flags]
public enum MyOptions
{
[Display(AutoGenerateField = false)]
None = 0,
[Display(Name = "Option 1 name")]
Opt1 = 1 << 1,
[Display(Name = "Option 2 name")]
Opt2 = 1 << 2,
[Display(Name = "Option 3 name")]
Opt3 = 1 << 3,
}
than, using:
<div class="editor-field">
#Html.LabelFor(m => m.Trade)
#Html.EditorFor(m => m.Trade, "Options")
</div>