MVC parent child kind of model form submit doesn't send child collection to controller - asp.net-mvc

I have a company model and it has employees list model as shown below
public class Company
{
[Required]
[Display(Name = "Company Name")]
public string Name { get; set; }
public List<EmployeeModel> Managers { get; set; }
}
and the Employee model as below
public class EmployeeModel
{
public string Name { get; set; }
public string Email { get; set; }
public string Phone { get; set; }
}
and my parent view is as shown below
#using (Html.BeginForm("CompanySignupSuccess", "Home", FormMethod.Post, new { #class = "horizontal-form", role = "form", enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary("", new { #class = "text-danger" })
<div>
<div class="form-group">
#Html.LabelFor(m => m.Name, new { #class = "control-label" })<span class="required">*</span>
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
</div>
<div class="form-group">
<label for="file">Logo:</label>
<input type="file" name="logo" id="logo" accept=".png,.jpg,.jpeg" />
</div>
<div id="managerList">
<div id="editorRowsManagers">
#foreach (var item in Model.Managers)
{
#Html.Partial("DetailsView", item)
}
</div>
</div>
<div class="form-group">
<input type="submit" class="btn btn-default pull-right" value="Send" />
</div>
</div>
}
and the partial view shown below
#model yourAssembly.EmployeeModel
<div style="border:1px solid;margin:20px; padding:10px;">
Manager Details:
<div class="form-group">
#Html.LabelFor(m => m.Name, new { #class = "control-label" })
#Html.TextBoxFor(m => m.Name, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "control-label" }) <span class="required">*</span>
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
<div class="form-group">
#Html.LabelFor(m => m.Phone, new { #class = "control-label" }) <span class="required">*</span>
#Html.TextBoxFor(m => m.Phone, new { #class = "form-control phoneno" })
</div>
</div>
When I click on submit button, the model that goes to controller does have only Name and Logo properties filled in and the list object(Managers) is null, so I am not sure what is that I am missing here. BTW, I used the list of employees , because I would like add more employees by having a 'Add' button, and the Add button will just render another partial view.
public ActionResult CompanySignupSuccess(Company model)
{
if (ModelState.IsValid)
{
//do some process
}
else
{
ModelState.AddModelError("", "Invalid Data entered.");
}
// If we got this far, something failed, redisplay form
return View("CompanySignup", Model);
}
Can anyone please help me on how to send the child list object along with some properties on parent class when the Submit button is hit.

You cannot use a partial to generate controls for a collection unless you pass the HtmlFieldPrefix (refer this answer for an example). However the correct way to do this is to use an EditorTemplate. Rename your partial to EmployeeModel.cshtml (i.e. to match the name of the class) and move it to the /Views/Shared/EditorTemplates folder (or /Views/YourControllerName/EditorTemplates folder).
Then replace your loop in the view with
#Html.EditorFor(m => m.Managers)
which will correctly generate the necessary name attributes for binding, i.e
<input ... name="Managers[0].Name" />
<input ... name="Managers[1].Name" />
etc (currently all your generating is duplicate name attributes (and duplicate id attributes which is invalid html)

Related

ASP.NET MVC - Null Object in ViewModel on POST

Upon POST of an ActionController I am receiving the great ole' object reference not set to an instance of an object error.
Basically I need the ID of the userRequest to be saved WITH the requestResponse. (Foreign Key here)
Here is the code.
ViewModel:
public class RequestResponseViewModel
{
public Models.Request userRequest { get; set; }
public Models.RequestResponse requestResponse { get; set; }
}
View: In debug here there is value in model.userRequest.ID
#model UserRequests.ViewModels.RequestResponseViewModel
#{
ViewBag.Title = "Create";
}
<h2>Admin Response to Request</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(model => model.requestResponse.Response,
htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-10">
#Html.TextAreaFor(model => model.requestResponse.Response, new {
#class = "form-control", #rows = 5 })
#Html.ValidationMessageFor(model =>
model.requestResponse.Response, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.userRequest.ID, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-2">
#Html.DisplayFor(model => model.userRequest.ID)
#Html.ValidationMessageFor(model => model.userRequest.ID, "", new { #class = "text-danger" })
</div>
#Html.LabelFor(model => model.requestResponse.Author, htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-3">
#Html.EditorFor(model => model.requestResponse.Author, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.requestResponse.Author, "", new { #class = "text-danger" })
</div>
#Html.LabelFor(model => model.requestResponse.CreateDate, htmlAttributes: new { #class = "control-label col-md-1" })
<div class="col-md-3">
<h5>#DateTime.Now</h5>
#Html.ValidationMessageFor(model => model.requestResponse.CreateDate, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-1">
<button type="reset" class="btn btn-default">Cancel</button>
<input type="submit" value="Create" class="btn btn-success" />
</div>
</div>
</div>
<hr />
<h3 class="text-success">Original Request</h3>
<div class="row">
<div class="col-md-10">
<h4>#Html.DisplayFor(model => model.userRequest.Title)</h4>
</div>
</div>
<div class="row">
<div class="col-md-10">
<h4>#Html.DisplayFor(model => model.userRequest.Description)</h4>
</div>
</div>
}
<div>
#Html.ActionLink("Back to Browse", "Browse","Change")
</div>
Get ActionResult:
public ActionResult Create(int id)
{
UserRequestContextDataContext db = new UserRequestContextDataContext();
var request = (from m in db.Requests
where m.ID == id
select new Models.Request()
{
ID = m.ID,
Title = m.Title,
Description = m.Description,
BusinessUnit = m.BusinessUnit,
Author = m.Author,
ModuleName = m.MenuItem,
RequestStatus = 2,
SubmitDate = m.SubmitDate,
Type = m.Type,
UrgencyNum = m.UrgencyLevel
}).FirstOrDefault();
var reqResponse = new Models.RequestResponse();
var viewModel = new RequestResponseViewModel
{
userRequest = request,
requestResponse = reqResponse
};
return View(viewModel);
}
The "viewModel" here has everything I need. It's lost somewhere between the ActionResults..
And Finally the Post ActionResult:
[HttpPost]
public ActionResult Create(RequestResponseViewModel _requestResponseViewModel)
{
try
{
if (ModelState.IsValid)
{
using (UserRequestContextDataContext db = new UserRequestContextDataContext())
{
RequestResponse reqRes = new RequestResponse();
reqRes.Response = _requestResponseViewModel.requestResponse.Response.ToString();
reqRes.RequestID = _requestResponseViewModel.userRequest.ID;
reqRes.Author = _requestResponseViewModel.requestResponse.Author.ToString();
reqRes.CreateDate = DateTime.Now;
db.RequestResponses.InsertOnSubmit(reqRes);
db.SubmitChanges();
}
}
return RedirectToAction("Browse","Change");
}
catch (Exception ex)
{
return View("Error", new HandleErrorInfo(ex, "Change", "Create"));
}
}
Using debug mode the userRequest object is NULL in the view model parameter of the POST method but requestResponse is FINE and populated as should.
Searching on this, it seemed most had issues with the naming convention in the view model but I've made sure there are no discrepancies there.
If there is a more clear way to do this workflow please mention.
#Html.DisplayFor does not create an HTML input element, but a simple string literal (for most types, some exceptions are listed in the docs: https://msdn.microsoft.com/en-us/library/ee407420(v=vs.118).aspx#Anchor_1).
So when you press submit, your browser will not send the ID back to the server because it sends only form data (e.g. data from input, textare, select fields). Using your browsers developer tools (F12) you can examine what is actually send to the server.
You can add a hidden input field using #Html.HiddenFor(model => model.userRequest.ID) or use a custom display template for the ID to automatically add a hidden input field. You could further use UIHint attributes to automatically select a display template. Both approaches are thoroughly documented (e.g. http://www.codeguru.com/csharp/.net/net_asp/mvc/using-display-templates-and-editor-templates-in-asp.net-mvc.htm).
Another reason the object could be NULL in the POST is due to forgetting to add the setters { get; set; } in your view model:
public Orders orders; --> missing { get; set; }
public class OrderViewModel
{
public Orders orders { get; set; }
public List<VendorJobTitleView> Jobs { get; set; }
public List<ManagerView> Managers { get; set; }
}

Upload a HttpPostedFileBase for image but always null

I am new to MVC and web programming.
My uploading image is working fine, but when I use almost the exact same code to allow user to modify its upload, it HttpPostedFileBase is always null. Driving me crazy...
here is the model
public class ModifyGenreViewModel
{
public int Id { get; set; }
[Display(Name = "Nom du style")]
public string Name { get; set; }
[Display(Name = "Image")]
public HttpPostedFileBase Image { get; set; }
}
and the view
#using (Html.BeginForm("ModifyGenre", "Upload", null, FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>#Resource.StyleCreationHeader</h4>
<hr />
#Html.ValidationMessageFor(model=>Model)
<div class="form-group" style="display:none">
#Html.LabelFor(model => model.Id, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.EditorFor(model => model.Id, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Name, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-5">
#Html.EditorFor(model => model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Name, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Image, new { #class = "control-label col-md-2" })
<div class="col-md-10">
<input type="file" data-val="true" id="ModifyGenreViewModel_Image" name="ModifyGenreViewModel.Image" />
#Html.ValidationMessageFor(model => model.Image, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="#Resource.Modify" class="btn btn-primary" />
</div>
</div>
</div>
}
When I set the breakpoint in my controller, I see the Id and the name, but Image is always null.
Thank's for your help!
The name property value of your file input should match with the view model property name for model binding to work properly.
Change the input field name to "Image"
<input type="file" data-val="true" id="ModifyGenreViewModel_Image" name="Image" />
Assuming your HttpPost action method accepts the ModifyGenreViewModel object as parameter.
[HttpPost]
public ActionResult ModifyGenre(ModifyGenreViewModel model)
{
// to do : return something
}
In model class change it to public String Image { get; set; }
In .cshtml page change it to #Html.TextBoxFor(m => m.Image, new {
type = "file", name="Image" })
In Controller you should use the name what you have decleared in html helper HttpPostedFileBase Image

What is the preferred way to standardise complex html views for data types?

I have code like this that I repeat through many MVC editing views. This example is the default way we display a checkbox, but similar repetition is found with other input types.
<div class="form-group">
#Html.LabelFor(model => model.IsLive, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-8 checkbox">
<div class="col-xs-1">
#Html.EditorFor(model => model.IsLive)
</div>
<div class="col-xs-10">
#Html.CheckboxLabelFor(model => model.IsLive)
</div>
</div>
<a class="infoonclick col-md-1" title="#Html.DisplayNameFor(model => model.IsLive)" data-content="#Html.DescriptionFor(model => model.IsLive)">
<span class="fa fa-info-circle"></span>
</a>
</div>
I am wondering what is the best way to DRY and standardise this?
I want to do something like #Html.DefaultCheckboxEditorFor(model => model.IsLive)
I tried creating a custom HtmlHelper, but this seemed to involve too many hard coded strings to be a good idea.
Rather I feel I should be using EditorTemplates for this, but I can't quite get the syntax right. The model for the view is a bool, but I need to get property specific stuff like the display name and descriptions.
#model bool
<div class="form-group">
#Html.LabelFor(model => model.IsLive, htmlAttributes: new { #class = "control-label col-md-3" })
<div class="col-md-8 checkbox">
<div class="col-xs-1">
#Html.EditorFor(model => model.IsLive)
</div>
<div class="col-xs-10">
#Html.CheckboxLabelFor(model => model.IsLive)
</div>
</div>
<a class="infoonclick col-md-1" title="#Html.DisplayNameFor(model => model.IsLive)" data-content="#Html.DescriptionFor(model => model.IsLive)">
<span class="fa fa-info-circle"></span>
</a>
</div>
I have a project where most of my views look like:
(This also works with multi-level deep complex objects, but not with any type of collection, like IEnumerable, although it could be modified to do so)
<h3>Edit existing page</h3>
<div class="col-xs-12">
#using (Html.BeginForm("Edit", "Page", FormMethod.Post, new { role = "role" }))
{
#Html.EditorForModel()
<input type="submit" value="Save" class="btn btn-primary" />
}
</div>
I think that's pretty cool. So the model looks like:
public class PageEditViewModel
{
[Editable(false)]
[DisplayName("Page Id")]
public Guid Id { get; set; }
[Editable(false)]
[DisplayName("Url to resource (format: '/my-resource' or '/sub/resource)'")]
public string Url { get; set; }
[Required]
[MaxLength(50, ErrorMessage = "Maximum Length of 50 Exceeded.")]
[DisplayName("Title for page (must match Url ex: 'My Resource' or 'Sub Resource'")]
public string PageTitle { get; set; }
[MaxLength(int.MaxValue, ErrorMessage = "Content Exceeded Maximum Length")]
[DataType(DataType.MultilineText)]
public string Content { get; set; }
}
I have some editor templates:
\Views\Shared\EditorTemplates\multilinetext.cshtml
#model object
#{
var htmlAttributes = this.ViewData.ModelMetadata.GetHtmlAttributes();
}
<div class="form-group #Html.ErrorClassFor(m => m, "has-error")">
#Html.LabelFor(m => m, new { #class = "control-label" })
<div class="controls">
#Html.TextAreaFor(
m => m,
8, 8,
htmlAttributes)
#Html.ValidationMessageFor(m => m, null, new { #class = "help-block" })
</div>
</div>
And it all magically works with the a modified version of object.cshtml:
#model object
#using System.Text;
#using System.Data;
#{
ViewDataDictionary viewData = Html.ViewContext.ViewData;
TemplateInfo templateInfo = viewData.TemplateInfo;
ModelMetadata modelMetadata = viewData.ModelMetadata;
System.Text.StringBuilder builder = new StringBuilder();
string result;
// DDB #224751
if (templateInfo.TemplateDepth > 2)
{
result = modelMetadata.Model == null ? modelMetadata.NullDisplayText
: modelMetadata.SimpleDisplayText;
}
foreach (var prop in modelMetadata.Properties.Where(pm =>
pm.ShowForEdit
//&& pm.ModelType != typeof(System.Data.EntityState)
&& !templateInfo.Visited(pm)
)
.OrderBy(pm => pm.Order))
{
//Type modelType = Model.GetType();
Type modelType = modelMetadata.ModelType;
System.Reflection.PropertyInfo pi = modelType.GetProperty(prop.PropertyName);
System.ComponentModel.DataAnnotations.DisplayAttribute attribute = pi.GetCustomAttributes(typeof(System.ComponentModel.DataAnnotations.DisplayAttribute), false).FirstOrDefault() as System.ComponentModel.DataAnnotations.DisplayAttribute;
if (attribute != null
&& !string.IsNullOrWhiteSpace(attribute.GetGroupName()))
{
//builder.Append(string.Format("<div>{0}</div>", attribute.GetGroupName()));
builder.Append(Html.Partial("Partial-GroupName", attribute.GetGroupName()));
}
builder.Append(Html.Editor(prop.PropertyName, prop.TemplateHint ?? prop.DataTypeName).ToHtmlString());
}
result = builder.ToString();
}
#Html.Raw(result)
Example output:
My EditFor templates are versions of MacawNL BootstrapEditorTemplates (which I have no affiliation with).

Field required attribute acidentially invoked but clicking a button

I have these fields, and I implemented required attribute on them.
#using (Html.BeginForm("Edit", "ChannelsGrid", FormMethod.Post, new {name = "channelForm", #class = "channelForm", #enctype = "multipart/form-data"}))
{
<div class="form-group">
#Html.HiddenFor(model => Model.Id)
<div class="row">
<div class="col-md-6">
#Html.Label("Part/Location", new {#class = "control-label"})
#Html.TextBox("PartLocation", null, new { #class = "form-control", #required = "required" })
</div>
<div class="col-md-6">
#Html.Label("Index", new {#class = "control-label"})
#Html.TextBox("Index", null, new {#class = "form-control"})
</div>
</div>
<div class="row">
<div class="col-md-6">
#Html.Label("Measurement", new {#class = "control-label"})
#Html.DropDownListFor(model => model.Measurement, (SelectList)ViewBag.Measurements, "-- Select Measurement --", new { #class = "form-control", #required = "required" })
</div>
<div class="col-md-6">
#Html.Label("Location", new {#class = "control-label"})
#Html.DropDownList("Directions", ViewBag.DirectionTypes as List<SelectListItem>, "-- Select Direction --", new { #class = "form-control", #required = "required" })
</div>
</div>
<div class="row">
<div class="col-md-6">
#Html.LabelFor(model => model.ChannelGroupId, new {#class = "control-label"})
#Html.DropDownListFor(x => x.ChannelGroupId, Model.ChannelGroups, "Select Channel Group", new {#class = "form-control"})
#Html.ValidationMessageFor(model => model.ChannelGroupId)
</div>
<div class="col-md-3">
<label class="control-label"></label>
<a href="#" id="addChannelGroup" class="form-control" style="border: none">
<i class="fa fa-plus-circle">Add Group</i>
</a>
</div>
<div class="col-md-3">
<label class="control-label"></label>
<a href="#" id="addMeasurement" class="form-control" style="border: none">
<i class="fa fa-plus-circle">Add Measurement</i>
</a>
</div>
</div>
<br/>
<div class="row">
<div class="col-md-6">
#Html.Label("Channel name: ", new {id = "channelName", #class = "control-label"})
</div>
<div class="col-md-6">
#Html.TextBox("HiddenTextBox", null, new {#class = "hidden"})
<div class="col-md-1">
#Html.TextBoxFor(a => a.Name, new {#class = "hidden"})
</div>
</div>
</div>
</div>
<div class="row" id="pnlAddChannelGroupName" style="display: none">
<div class="col-md-6">
<label class="control-label">Channel Group Name :</label>
<input type="text" id="ChannelGroupName" name="ChannelGroupName" class="form-control"/>
<input type="button" value="Cancel" id="channelGroupButton" />
#*<button id="channelGroupButton">Cancel</button>*#
</div>
</div>
<div class="row" id="pnlMeasurement" style="display: none">
<div class="col-md-6">
#Html.Label("Measurement :", new {#class = "control-label"})
#Html.TextBox("MeasurementName", null, new {#class = "form-control"})
<input type="button" value="Cancel" id="measurementButton" />
#*<button id="measurementButton">Cancel</button>*#
</div>
</div>
}
I also have two buttons which are used to toggle other textboxes in this form. Here is the code.
<div class="row" id="pnlAddChannelGroupName" style="display: none">
<div class="col-md-6">
<label class="control-label">Channel Group Name :</label>
<input type="text" id="ChannelGroupName" name="ChannelGroupName" class="form-control"/>
<button id="channelGroupButton">Cancel</button>
</div>
</div>
<div class="row" id="pnlMeasurement" style="display: none">
<div class="col-md-6">
#Html.Label("Measurement :", new {#class = "control-label"})
#Html.TextBox("MeasurementName", null, new {#class = "form-control"})
<button id="measurementButton">Cancel</button>
</div>
</div>
The problem is whenever I click these two Cancel buttons in that field, the three fields seems to be invoked and there is brown border around the textbox dropdownlist. I guess these field have been submitted. But I thought I use button element instead of type button of an input so I can eliminate the submitting action of the button, right? Any clues? And how can I click these Cancel buttons withouts invoking validation in these other field?
Edited: I changed all the buttons to input type="button" and the validation of these other field dissapeared. Can someone explain?
This is my viewmodel:
namespace CrashTestScheduler.Entity.ViewModel
{
public class ChannelViewModel
{
public int Id { get; set; }
//[Display(Name = "Name")]
//[Required(ErrorMessage = "Please specify the channel name.")]
public string Name { get; set; }
public string Description { get; set; }
public string ChannelGroupName { get; set; }
public string MeasurementName { get; set; }
[Required(ErrorMessage = "Please select a channel group.")]
public int ChannelGroupId { get; set; }
public IEnumerable<SelectListItem> ChannelGroups { get; set; }
//[Required]
public string Measurement { get; set; }
}
}
The reason your form is submitting when clicking buttons is that the default action for a <button> element is type="submit" (refer documentation). You need to explicitly set the type attribute
<button type="button" ....>
However you have numerous issues with your approach.
By removing the [Required] attributes and using the required =
"required" html attribute, you now need to include manual
validation on the controller (never trust the user!)
Your mixing up Razor and manual html in the view, potentially
creating problems for model binding. Some of your label elements
wont work. (e.g. the first one is associated with a control named
"Part/Location" but there is no control named "Part/Location").
The user interface where your force users to click buttons to swap
between textboxes and dropdown lists is confusing and a sure way to
lose customers. Instead you should use an autocomplete control such
as jQuery Autocomplete which allows selection from a list or
direct text entry.
Your view model should contain validation attributes for its properties and can be simplified to
public class ChannelViewModel
{
public int Id { get; set; }
[Display(Name = "Part/Location")]
[Required]
public string PartLocation { get; set; }
public string Index { get; set; }
[Required]
public string Measurement { get; set; }
[Required]
[Display(Name = "Location")]
public int Direction { get; set; }
.... // other properties
public SelectList DirectionList { get; set; }
}
View
#Html.HiddenFor(model => Model.Id)
#Html.LabelFor(m => m.PartLocation, new {#class = "control-label"})
#Html.TextBoxFor(m => m.PartLocation, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.PartLocation)
#Html.LabelFor(m => m.Index, new {#class = "control-label"})
#Html.TextBoxFor(m => m.Index, new {#class = "form-control"})
#Html.LabelFor(m => m.Measurement, new {#class = "control-label"})
#Html.TextBoxFor(m => m.Measurement, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Measurement)
#Html.LabelFor(m => m.Direction, new {#class = "control-label"})
#Html.DropDownListFor(m => m.Direction, Model.DirectionList, "-- Select Direction --", new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Direction)
.... // more controls
The attach the autocomplete to $(#Measurement).autocomplete({...
This will give you client and server side validation out of the box, and a better user interface.

modelstate.isvalid not getting all the errors

I have this model :
[Required(ErrorMessage = "Please provide a valid EmailAddress")]
[EmailAddress]
[Display(Name = "Email")]
public string Email { get; set; }
[Required(ErrorMessage = "Please provide a company name")]
[Display(Name = "Company")]
public string CompanyName { get; set; }
[Required(ErrorMessage = "Please provide a username")]
[Display(Name = "Username")]
public string UserName { get; set; }
[Required(ErrorMessage = "Please select at least one language")]
public int[] SelectedLanguages { get; set; }
[Required(ErrorMessage = "Please select at least one business unit")]
public int[] SelectedBusinessUnits { get; set; }
Now when I do a post from my form using this model and I don't provide any of the values, I only get errormessages for Email, Company and UserName.
I don't get messages for the SelectedLanguages or the SelectedBusinessUnits.
What am i doing wrong?
THis is the view
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
#Html.ValidationSummary("", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.CompanyName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.CompanyName, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.UserName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.UserName, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.Email, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.Email, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#foreach (var la in Model.Languages)
{
<input type="checkbox"
name="SelectedLanguages" value="#la.Id" id="#la.Id" />
<label for="#la">#la.Title</label>
}
</div>
<div class="form-group">
#foreach (var bu in Model.BusinessUnits)
{
<input type="checkbox"
name="SelectedBusinessUnits" value="#bu.Id" id="#bu.Id" />
<label for="#bu.Id">#bu.Title</label>
}
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
I think you have to go the way of writing a custom validation routine accompanied with a ValidationAttribute. Don't think a simple "out-of-the-box" validator exists for checking if one or more values are present in an array.
Check out this SO post to point you in the right direction.
Basic setup:
public class ArrayContainsValueAttribute: ValidationAttribute
{
// your checks here (pseudo)
if(!array.Any())
return false;
return true;
}
[ArrayContainsValue(ErrorMessage = "Please select at least one business unit")]
public int[] SelectedBusinessUnits { get; set; }

Resources