I have a dropdownlist which I would like to be optional, however, the ModelState.IsValid check is trying to validate the property. Is there a way to tell it the property is optional?
Here is my code:
<h2>New Version</h2>
#using (Html.BeginForm()) {
<div>Version Number: #Html.TextBoxFor(m => m.Number)</div>
<div>Enabled: #Html.CheckBoxFor(m => m.IsActive)</div>
<div></div>
<div>
Template (optional):
#Html.DropDownListFor(m => m.TemplateVersionId, new SelectList(Model.CurrentVersions, "VersionId", "Number"),
"-- Select Template --")
</div>
<input type="submit" value="Save" />
#Html.ActionLink("Cancel", "Index");
}
and my ViewModel:
public class AddVersionViewModel
{
public double Number { get; set; }
public bool IsActive { get; set; }
public int TemplateVersionId { get; set; }
public ICollection<Version> CurrentVersions { get; set; }
}
I want the TemplateVersionId to be optional.
Change it to an int? to make it nullable.
When you create Nullable items it becomes optional in forms
public class AddVersionViewModel
{
public double Number { get; set; }
public bool IsActive { get; set; }
public int? TemplateVersionId { get; set; }
public ICollection<Version> CurrentVersions { get; set; }
}
Related
Scenario
I have a problem that utilizes a jquery repeater that way I can keep adding records in this case qualification records.
Problem
The problem I am experiencing is that I cannot get a Yes/No dropdown or checkbox to work or display the value that it reads from the database. As you can see,from the screenshot I can't select the value "no" to be displayed in my dropdown list, if true was selected, I wouldnt be able to get my checkbox to be "ticked"
The commented area of code shows some of the methods I've used, As you can see, I cant exactly bind act (Correct me here if im wrong) because it's part of another class so I cant say "Model.historyLead" or Model.act.historyLead.
I am returning all the other values but it's just the checkbox or dropdown list is not working for me.
I would greatly appreciate any help in solving this.
Regards
Part of my edit view
#foreach (var item in Model.act)
{
<div data-repeater-item class="mt-repeater-item">
<div class="mt-repeater-input">
<label>Institution</label>
<input type="text" class="form-control" name="hisotryInput" value="#item.hisotryInput" />
</div>
<div class="mt-repeater-input">
<label>Description</label>
<div class="col-md-10">
#Html.TextArea("hisotrydescrip",item.hisotrydescrip, new { #class = "form-control", cols = 50, #rows = 5,#style="width:290px" })
</div>
</div>
<div class="mt-repeater-input">
<label>Lead Consultant?</label>
#*#Html.DropDownList("historyLead", null, String.Empty, new { #class = "form-control ", #Value = #item.historyLead })*#
#*#Html.CheckBox("historyLead", new { htmlAttributes = new { #class = "form-control",#value=#item.historyLead } })*#
<input type="checkbox" class="form-control" name="historyLead" value=#item.historyLead />
#*<select name="historyLead" >
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="vw">VW</option>
<option value="audi" selected>Audi</option>
</select>*#
</div>
And model used
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Web;
namespace CARICAD_App.Models
{
public class repeatViewModel
{
[Display(Name = "textinput")]
public string textinput { get; set; }
}
public class CON_consultantInfoVM
{
[DisplayName("Age Range")]
public Nullable<int> ageRange { get; set; }
public int id { get; set; }
[DisplayName("Image")]
public string image { get; set; }
[DisplayName("Consultant ID")]
public string consultID { get; set; }
[DisplayName("First Name")]
[Required]
public string firstName { get; set; }
...
public REF_country REF_country { get; set; }
public REF_nationality REF_nationality { get; set; }
public List<actVm> act { get; set; }
}
public class actVm
{
public Nullable<int> id { get; set; }
public string consultID { get; set; }
public string textinput { get; set; }
public string untypedinput { get; set; }
public string dateinput { get; set; }
public string textareainput { get; set; }
public string radioinput { get; set; }
public string selectinput { get; set; }
public string activities { get; set; }
public string hisotryInput { get; set; }
public string historydateinput { get; set; }
public string hisotrydescrip { get; set; }
public string historydateinputTo { get; set; }
public string historyLead { get; set; }
public bool historyCo { get; set; }
public List<string> multipleselectinput { get; set; }
}
}
Try adding a checked attribute when your condition is true:
<input type="checkbox" name="historyLead" value="#item.historyLead" #(item.historyLead== "Yes" ? "checked='checked'" : "") class="form-control" />
You could also add a boolean property to your viewmodel and then use CheckBoxFor as shown here
You misunderstand how checkbox works.
Value of checkbox is sent to server when it is checked
If checkbox is not checked no Value is sent to server
With this two rules you can say that Value should be Yes so it will post back the value of Yes to server if checked. If unchecked you can add some logic if (String.IsNullOrEmpty(historyLead)) historyLead = "No".
But i would suggest changing property historyLead to Boolean and setting value of checkbox to True. Because of default value it would become False in case if it was unchecked.
HTML.BeginCollectionItem does not return values to the controller. It always return NULL in the controller. I am not sure if has got anything to do if there is a partial view within another partial view. Below is the snippet of the code/view.
ProductEditModel
public class ProductEditModel
{
// Product details displayed on edit form
public Product ProductModel { get; set; }
public IList<ProductAssetAudioEditModel> ProductAssetAudios { get; set;}
}
ProductAssetAudioEditModel
public class ProductAssetAudioEditModel
{
public int ProductId { get; set; }
public int? ProductAssetId { get; set; }
public virtual IList<ProductAssetResourceEditModel> ProductAssetResources { get; set; }
}
ProductAssetResourceEditModel
public class ProductAssetResourceEditModel
{
public int? ProductAssetResourceId { get; set; }
public int ProductAssetId { get; set; }
public int ResourceNumber { get; set; }
public int? ElectronicFileId { get; set; }
public ElectronicFile ElectronicFile { get; set; }
}
ProductEditView.cshtml
<div id="audio">
#foreach (ProductAssetAudioEditModel audio in Model.ProductAssetAudios)
{
Html.RenderPartial("_ProductAssetAudioRow", audio);
}
</div>
_ProductAssetAudioRow.cshtml
#using (Html.BeginCollectionItem("ProductAssetAudios"))
{
....
<tbody>
#foreach (var resource in Model.ProductAssetResources)
{
Html.RenderPartial("_ProductAssetAudioResource", resource);
}
</tbody>
.....
}
_ProductAssetAudioResource
#using (Html.BeginCollectionItem("ProductAssetResources"))
{
#Html.HiddenFor(m => Model.ProductAssetResourceId)
#Html.HiddenFor(m => Model.ProductAssetId)
<td>
#if (Model.ElectronicFileId.HasValue)
{
#Html.HiddenFor(model => model.ElectronicFileId)
#Html.ActionLink(Model.ElectronicFile.FileName, "Details", "File", new { id = Model.ElectronicFileId, area = "Edi" }, null);
}
</td>
<td>
#Html.EditorFor(c => Model.TrackTitle)
</td>
}
In the controller , ProductAssetResources is NULL even though edit page binds the properties correctly for editing.
I am not sure what I am missing here.
-Alan-
When passing the model from my view to my controller, the data is all null. I was able to successfully pass it using an ActionLink but I don't think that is the best way; for security reasons (I do not want sensitive data in the querystring).
My models
public class DashboardModel
{
// Dasboard quick numbers
public int TotalUsers { get; set; }
public int TotalUnauthUsers { get; set; }
public int GamesPlayed { get; set; }
public int AssociatedGroups { get; set; }
public int TotalGroups { get; set; }
// Dashboard table
public IEnumerable<ManageUserData> UnauthUsers { get; set; }
}
public class ManageUserData
{
public string UserName { get; set; }
public int AlternateId { get; set; }
public string Email { get; set; }
public string Role { get; set; }
public IEnumerable<string> InvestigatorGroups { get; set; }
public string Institution { get; set; }
// User status
public bool AccountLocked { get; set; }
public bool EmailConfirmed { get; set; }
}
Snippet of my view
#model TestGame.ViewModels.DashboardModel
#foreach (var user in Model.UnauthUsers)
{
<tr>
<td>#user.UserName</td>
<td>#user.AlternateId</td>
<td>#user.Email</td>
<td>#user.Role</td>
<td>
#if (!user.EmailConfirmed)
{
<div class="text-warning">Unconfirmed Email</div>
}
#if (user.AccountLocked)
{
<div class="text-danger">Account Locked</div>
}
</td>
<td>
#if (user.AccountLocked || !user.EmailConfirmed)
{
using (Html.BeginForm("Manage", "Admin", FormMethod.Post))
{
#Html.HiddenFor(x => user.UserName)
#Html.HiddenFor(x => user.Email)
<input type="submit" value="Manage" />
You have to make sure the path starts with the object being posted back; what you have will work great if the action being posted to (HttpPost Admin/Manage action) takes an object of type User; if it takes an object of the model type, change your form to the following:
for (var i = 0; i < Model.UnAuthUsers.Count; i++)
using (Html.BeginForm("Manage", "Admin", FormMethod.Post))
{
#Html.HiddenFor(x => x.UnAuthUsers[i].UserName)
#Html.HiddenFor(x => x.UnAuthUsers[i].Email)
<input type="submit" value="Manage" />
Creating a reference from the model (being x) will do the trick.
EDIT: Based on comments, add two properties to your model:
public class DashboardModel
{
public string SelectedUserName { get; set; }
public string SelectedEmail { get; set; }
}
In your form, render a hidden for for that name; I've had trouble using HiddenFor, so I've in the past used the hidden directly:
using (Html.BeginForm("Manage", "Admin", FormMethod.Post))
{
<input type="hidden" name="#Html.NameFor(i => i.SelectedUserName)" value="#Model.UnauthUsers[i].UserName" />
<input type="hidden" name="#Html.NameFor(i => i.SelectedEmail)" .. />
And upon submitting the form, the user from that form will be posted back via the model, via these new properties.
There is 1 form on which i will ask for Academic Details for :
Graduation
Post Graduation(Masters)
Professional Qualification.
So far any user say UserId="1" 3 entries will be created in my AcademicMaster each for bachelor,Master(Post Graduation) and Professional Qualification.
My Database AcademicMaster table fields and datamodel:
Id,Qualification(GraduationCourses),Acheievement,UserId
View Model:
public class AcademicViewModel
{
public int Id { get; set; }
public virtual Graduation Graduation{ get; set; }
public virtual PostGraduation PostGraduation{ get; set; }
public virtual ProfessionalQualification ProfessionalQualification{ get; set; }
}
public class Graduation
{
public string BachelorQualification { get; set; }
public string BachelorAchievement { get; set; }
}
public class PostGraduation
{
public string MasterQualification { get; set; }
public string MasterAchievement { get; set; }
}
public class ProfessionalQualification
{
public string ProfessionalQualifications { get; set; }
}
So my View is like this:
#model AcademicViewModel
#{
IEnumerable<SelectListItem> graduationList = ViewBag.GraduationList;
IEnumerable<SelectListItem> postGraduationList = ViewBag.PostGraduationList;
}
#using (Html.BeginForm())
{
<div class="row">
Bachelors
#Html.DropDownListFor(model => model.Graduation.Qualification, graduationList)
</div>
#Html.TextAreaFor(model => model.Graduation.Achievement)
<div class="row">
MASTERS
#Html.DropDownListFor(model => model.PostGraduation.Qualification, postGraduationList)
</div>
#Html.TextAreaFor(model => model.PostGraduation.Achievement)
<div class="row">
PROFESSIONAL QUALIFITCATION
#Html.TextAreaFor(model => model.ProfessionalQualification.ProfessionalQualifications)
</div>
<input type="submit" value="Save">
}
This is my Controller:
[HttpPost]
public ActionResult MyController(AcademicViewModel model)
{
//Actions
}
So is my View Model structure appropriate and how to create 3 entries in AcademicMaster Table??
I will start by saying that having one table may not be the best choice (what happens if later you start adding additional properties which may be applicable to Graduation that are not applicable to Professional - for example YearOfGraduation - you could end up with a huge number of fields, many of which may have null values.
However, if you want one table, then at least add another field so that you can identify if the data is related to Graduation, PostGraduation or Professional. The associated data model for the AcademicMasters table would be
public class AcademicMaster
{
public int ID { get; set; }
public string Type { get; set; } // may be an enum?
public string Qualification { get; set; }
public string Achievement { get; set; }
public int UserID { get; set; }
}
Side note: It might be better to use an enum for the Type property
public enum AcademicType
{
Graduation,
PostGraduation,
Professional
}
There does not seem to be any need to your current Graduation, PostGraduation and ProfessionalQualification models and your view model should be
public class AcademicViewModel
{
public string GraduationQualification { get; set; }
public string GraduationAchievement { get; set; }
public string PostGraduationQualification { get; set; }
public string PostGraduationAchievement { get; set; }
public string ProfessionalAchievement { get; set; }
public IEnumerable<SelectListItem> GraduationList { get; set; }
public IEnumerable<SelectListItem> PostGraduationList { get; set; }
}
Side notes: Its not clear what your current ProfessionalQualifications property is - does that get assigned to the Qualification field or the Acheievement field in the database? Since your using a view model, then it should include the SelectList's rather that using ViewBag.
Then your view will be
#model AcademicViewModel
#using (Html.BeginForm())
{
<h2>Graduation</h2>
#Html.DropDownListFor(m => m.GraduationQualification, Model.GraduationList)
#Html.TextAreaFor(m => m.GraduationAchievement)
... // repeat for PostGraduation and Professional
<input type="submit" value="Save">
}
And the POST method would be
[HttpPost]
public ActionResult MyController(AcademicViewModel model) // should be named Create?
{
var userID = ....
AcademicMaster graduation = new AcademicMaster
{
Type = AcademicType.Graduation,
Qualification = model.GraduationAchievement,
Achievement = model.GraduationAchievement,
UserId = userID;
};
db.AcademicMasters.Add(graduation);
// Repeat for PostGraduation and Professional
db.SaveChanges();
// redirect?
}
I have a dashboard on my MVC 4 site that in part displays a list of data from one db table (my database was generated using the Entity Framework code-first method). The data being displayed is for a list of orders and the information that goes along with that order. Now, I'm trying to add the ability to add additional quantities for the same order (ex: I need this order quoted for 10, 25, 50 and 100 pieces). Right next to the edit, details, and delete options on each row is an add button where the user would then go to add another quantity. However, in testing, when I go to submit a quantity, the validation error comes up saying that the value entered is invalid when it should be a completely valid input. Can someone please help, because I can't figure out why this is happening. Here's some of the relevant code:
Models:
General_Info.cs
public class General_Info
{
[Key]
public int Quote_ID { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
public DateTime Open_Quote { get; set; }
public string Customer_Name { get; set; }
public string OEM_Name { get; set; }
public int Qty { get; set; }
public string Fab_Drawing_Num { get; set; }
public string Rfq_Num { get; set; }
public string Rev_Num { get; set; }
public string Group_Number { get; set; }
public General_Info()
{
Quantitys = new HashSet<Quantity>();
Quote_Datas = new HashSet<Quote_Data>();
}
public virtual ICollection<Quantity> quantitys { get; set; }
}
Quantity.cs
public class Quantity
{
[Key]
public int Qty_ID { get; set; }
public string Group_Number { get; set; } // foreign key
public int quantity { get; set; }
public General_Info General_Info { get; set; }
}
Dashboard Controller:
[HttpGet]
public ActionResult AddQuantity(int Group_Num = 0)
{
return View();
}
[HttpPost]
public ActionResult AddQuantity(Quantity quantity)
{
if (ModelState.IsValid)
{
db.Quantitys.Add(quantity);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(quantity);
}
View
AddQuantity.cshtml
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Quantity</legend>
<div class="editor-label">
#Html.LabelFor(model => model.quantity)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.quantity)
#Html.ValidationMessageFor(model => model.quantity)
</div>
<p>
<input type="submit" value="Add Qty" />
</p>
</fieldset>
}
As you can see, in my model quantity is an integer, and if I enter an integer into my form the validation error is thrown.
Thanks in advance to anyone who can help, I appreciate it.
if you change your binding model name, that should do it
[HttpPost]
public ActionResult AddQuantity(Quantity model)