I don't know why, the Model is not binding to the Create Action:
ViewModel:
public class AddressContactViewModel
{
// Primary properties
public int Id { get; set; }
public string Contact { get; set; }
// Navigation properties
[Display(ResourceType = typeof(HeelpResources), Name = "AddressContactViewModelNameLabel")]
[Required(ErrorMessageResourceName = "ErrorMsgRequiredField", ErrorMessageResourceType = typeof(HeelpResources))]
public int ContactType_Id { get; set; }
public int Address_Id { get; set; }
// ViewModel dropdownlists
public IEnumerable<SelectListItem> ContactTypeList { get; set; }
}
View:
#model Heelp.ViewModels.AddressContactViewModel
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Address_Id)
<fieldset>
<legend>AddressContactViewModel</legend>
<div id="year">
#Html.DisplayNameFor(m => m.ContactType_Id)
#Html.DropDownListFor(m => m.ContactType_Id, Model.ContactTypeList, HeelpResources.AddressContactViewModelContactTypesListDropDownFirstRecord)
#Html.ValidationMessageFor(m => m.ContactType_Id)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Contact)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.Contact)
#Html.ValidationMessageFor(m => m.Contact)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
Action Post:
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult ContactCreate(AddressContactViewModel contact)
{
var contactDto = Mapper.Map<AddressContactViewModel, AddressContactDto>(contact);
_addressContactService.Create(contactDto);
return RedirectToAction(MVC.Address.ContactList());
}
EDIT: Get:
public virtual ActionResult ContactCreate(int addressId)
{
var model = new AddressContactViewModel
{
Address_Id = addressId,
ContactTypeList = ContactTypeDropDownList()
};
return View(model);
}
When I submit the Form, I receive "null" in the contact parameter of the ContactCreate action, why is this happening?
Thanks
Unbelievable, I found the problem, the parameter of the action has the same name of a field in the ViewModel, a change of the parameter name and everything works find:
[HttpPost]
[ValidateAntiForgeryToken]
public virtual ActionResult ContactCreate(AddressContactViewModel addressContact) // HERE I CHANGE FROM contact TO addressContact AND THE PROBLEM GET SOLVED
{
var contactDto = Mapper.Map<AddressContactViewModel, AddressContactDto>(addressContact);
_addressContactService.Create(contactDto);
return RedirectToAction(MVC.Address.ContactList(addressContact.Address_Id));
}
I ran into this same problem on my last app. try encompassing the button and the field you want to submit into the same div:
#model Heelp.ViewModels.AddressContactViewModel
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Address_Id)
<fieldset>
<legend>AddressContactViewModel</legend>
<div id="year">
#Html.DisplayNameFor(m => m.ContactType_Id)
#Html.DropDownListFor(m => m.ContactType_Id, Model.ContactTypeList, HeelpResources.AddressContactViewModelContactTypesListDropDownFirstRecord)
#Html.ValidationMessageFor(m => m.ContactType_Id)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Contact)
</div>
<div class="editor-field">
#Html.TextBoxFor(m => m.Contact)
#Html.ValidationMessageFor(m => m.Contact)
<input type="submit" value="Create" />
</div>
</fieldset>
}
Related
I need to create a form to register.
the example of form will look like this
how do I display the value in the red circle in the form? (the value is from database)
My controller
namespace Insurance.Controllers
{
public class FlexiPAController : Controller
{
//
// GET: /FlexiPA/
public ActionResult RegisterFlexiPA()
{
return View();
}
public ActionResult RegisterFire()
{
return View();
}
public ActionResult RegisterMotor()
{
return View();
}
}
}
My ViewModel
namespace Insurance.ViewModels
{
public class RegisterInfoPA
{
public register reg { get; set; }
public infoPA infoFlexiPA { get; set; }
public personalInfo pinfo { get; set; }
public List<maritalInfo> minfo { get; set; }
public childInfo cInfo { get; set; }
}
}
My view
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<!--TITLE-->
<div class="editor-label">
Title
</div>
<div class="editor-field">
#Html.EditorFor(model => model.reg.title)
#Html.ValidationMessageFor(model => model.reg.title)
</div>
<!--NAME-->
<div class="editor-label">
Name
</div>
<div class="editor-field">
#Html.EditorFor(model => model.reg.registerNm)
#Html.ValidationMessageFor(model => model.reg.registerNm)
</div>
<!--IC NO-->
<div class="editor-label">
IC No
</div>
<div class="editor-field">
#Html.EditorFor(model => model.reg.identityNo)
#Html.ValidationMessageFor(model => model.reg.identityNo)
</div>
<!--GENDER-->
<div class="editor-label">
Gender
</div>
<div class="editor-field">
#Html.EditorFor(model => model.pinfo.gender)
#Html.ValidationMessageFor(model => model.pinfo.gender)
</div>
<!--Marital Status-->
<div class="editor-label">
**Marital Status**
</div>
<div class="editor-field">
</div>
Wanted to make the checkbox here for marital status eg :single,widowed,married
I am new to mvc, really appreciate your helps.
Try this
Let's try one controller first
Your Controller
namespace Insurance.Controllers
{
public class FlexiPAController : Controller
{
//
// GET: /FlexiPA/
DATABASENAME db = new DATABSENAME (); //ESTABLISHING CONNECTION TO DATABASE
public ActionResult RegisterFlexiPA()
{
using (var dataBase = new DATABASENAME ())
{
var model = new RegisterInfoPA()
{
minfo = dataBase.maritalInfoes.ToList(),
//IF YOU WISH TO ADD MORE
};
return View(model);
}
}
Your ViewModel
change you marital info to IEnurumerable instead of List
public IEnumerable<maritalInfo> minfo { get; set; }
Your View
I would like to suggest you to make radiobutton instead of checkbox, because surely you can only choose one,eg: either single or married. Thus, it is highly preferred to use radiobutton
<div>
Marital Status
#foreach (var item in Model.minfo)
{
#Html.RadioButtonFor(model => model.pinfo.maritalId, item.maritalId)#Html.Label(item.maritalStatNm)
}
</div>
This is how you display, then in the controller you just need to save it.
You can use :
#foreach(var item in Model.minfo)
{
#Html.EditorFor(o => item)
}
Create a partial view called maritalInfo.cshtml. Put this partial in Views/Shared/DisplayTemplates.
In the partial :
#model maritalInfo
<!--Marital Status Name and Value depend on your maritalInfo Model-->
<div class="editor-label">
#Html.LabelFor(o => Model.Name)
</div>
<div class="editor-field">
#Html.CheckBoxFor(o => Model.Value)
</div>
This question already has answers here:
The ViewData item that has the key 'MY KEY' is of type 'System.String' but must be of type 'IEnumerable<SelectListItem>'
(9 answers)
Closed 7 years ago.
I'm binding Categories and Genders in Dropdownlist. My Model has two attributes Mapped to the columns in other tables :
[Required(ErrorMessage = "Choose your category")]
public string Category { get; set; }
[ForeignKey("Category")]
[NotMapped]
public virtual Category Category_Name { get; set; }
[Required(ErrorMessage = "Choose your category")]
public string Gender { get; set; }
[ForeignKey("Gender")]
[NotMapped]
public virtual Gender Gender_Name { get; set; }
My ProductsController have a method called "Create" which is used for uploading
public ActionResult Create()
{
ViewBag.Category = new SelectList(
db.Categories.ToList(),
"Category_ID",
"Category_Name")
;
ViewBag.Gender = new SelectList(
db.Genders.ToList(),
"Gender_ID",
"Gender_Name"
);
return View();
}
//
// POST: /Products/Create
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(Products products)
{
if (products.Image.ContentLength > (2 * 1024 * 1024))
{
ModelState.AddModelError("CustomError", "The Size of the
Image is 2MB");
return View();
}
if (!(products.Image.ContentType == "image/jpeg" ||
products.Image.ContentType == "image/gif"))
{
ModelState.AddModelError("CustomError", "File type allowed :
jpeg and gif");
return View();
}
byte[] data = new byte[products.Image.ContentLength];
products.Image.InputStream.Read(data, 0,
products.Image.ContentLength);
products.Product_Photo = data;
db.Products.Add(products);
db.SaveChanges();
return View(products);
}
The Corresponding View is :
#model eKart.Models.Products
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm("Create", "Products", FormMethod.Post, new { enctype
= "multipart/form-data" }))
{
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>Products</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Product_Name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Product_Name)
#Html.ValidationMessageFor(model => model.Product_Name)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Product_Quantity)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Product_Quantity)
#Html.ValidationMessageFor(model => model.Product_Quantity)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Product_Price)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Product_Price)
#Html.ValidationMessageFor(model => model.Product_Price)
</div>
<div>
#Html.LabelFor(model=>model.Product_Photo)
</div>
<div>
#Html.TextBoxFor(model=> model.Image, new{type="file"})
#Html.ValidationMessage("CustomError")
</div>
<div class ="editor-label">
#Html.LabelFor(model => model.Category)
</div>
<div class="editor-field">
#Html.DropDownList("Category",
(SelectList)ViewBag.Category,"Choose Category")
#Html.ValidationMessageFor(model=>model.Category)
</div>
<div class ="editor-label">
#Html.LabelFor(model=>model.Gender)
</div>
<div class ="editor-field">
#Html.DropDownList("Gender",(SelectList)ViewBag.Gender,"Choose
Gender")
#Html.ValidationMessageFor(model=>model.Gender)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
When I Submit the form I hit the error at "Category" which is mentioned above.I checked StackOverFlow but didn't find useful information.I really wanna know what's going on and where I'm doing wrong.Thanks in advance your help
Add a new property in your class:
Model:
[Required(ErrorMessage = "Choose your category")]
public string Category { get; set; }
public List<System.Web.Mvc.SelectListItem> CategoryList { get; set; }
Controller:
public ActionResult Create()
{
var model = new Products();
model.CategoryList = db.Categories.Select(x => new SelectListItem
{
Text = x.CategoryName,
Value = x.CategoryName
}).ToList();
return View(model);
}
EDIT: As StephenMuecke said in his comment you need to reassign the values to your CategoryList Property when ModelState is not valid.
[HttpPost]
public ActionResult Create(Product product)
{
if(ModelState.IsValid)
{
// Code here
}
product.CategoryList = db.Categories.Select(x => new SelectListItem
{
Text = x.CategoryName,
Value = x.CategoryName
}).ToList();
return View(product);
}
View:
<div class ="editor-label">
#Html.LabelFor(model => model.Category)
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.Category, Model.CategoryList, "Choose category")
#Html.ValidationMessageFor(model=>model.Category)
</div>
Do the same in 'Gender'
I am new to MVC 4.
I am receiving the following error:
Object reference not set to an instance of an object. Line 47:#Html.ActionLink("Back to List", "Index", new { id = Model.RestaurantId })
Here is my view that is causing the error (please see the last couple of lines):
#model OdeToFood.Models.RestaurantReview
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<legend>New Review</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Rating)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Rating)
#Html.ValidationMessageFor(model => model.Rating)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Body)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Body)
#Html.ValidationMessageFor(model => model.Body)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ReviewerName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ReviewerName)
#Html.ValidationMessageFor(model => model.ReviewerName)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index", new { id = Model.RestaurantId })
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Here is my controller action that is being called when the Back To List link is clicked:
public ActionResult Index([Bind(Prefix="id")]int restaurantId)
{
var restaurant = _db.Restaurants.Find(restaurantId);
if (restaurant != null) {
return View(restaurant);
}
return HttpNotFound();
}
And here is the RestaurantReview model that is being strongly-typed in the view:
public class RestaurantReview
{
public int Id { get; set; }
public int Rating { get; set; }
public string Body { get; set; }
public string ReviewerName { get; set; }
public int RestaurantId { get; set; }
}
Any help would be muchly appreciated.
Cheers!
In your code you are showing the Create view, and the Index controller. Check if in the Create controller you are passing the Model, or check if it needs model.
The Main Controller
public class TestPartialController : Controller
{
//
// GET: /TestPartial/
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Main model)
{
HttpContext.Items.Add("MainModel", model);
return View();
}
public ActionResult PartialA()
{
return PartialView();
}
[HttpPost]
public ActionResult PartialA(PartialA a)
{
if (HttpContext.Items["MainModel"] != null)
{
Main model =(Main) HttpContext.Items["MainModel"];
model.PA = a;
}
return PartialView();
}
public ActionResult PartialB()
{
return PartialView();
}
[HttpPost]
public ActionResult PartialB(PartialB b)
{
if (HttpContext.Items["MainModel"] != null)
{
Main model = (Main)HttpContext.Items["MainModel"];
model.PB = b;
}
SubmitDatatoDB();
return PartialView();
}
public void SubmitDatatoDB()
{
if (HttpContext.Items["MainModel"] != null)
{
Main model = (Main)HttpContext.Items["MainModel"];
//SubmitDatatoDB
}
}
}
Models:-
namespace TestingMVC4.Models
{
public class Main
{
public string Main1 { get; set; }
public string Main2 { get; set; }
public virtual PartialA PA { get; set; }
public virtual PartialB PB { get; set; }
}
public class PartialA
{
public string UserName { get; set; }
public string UserID { get; set; }
}
public class PartialB
{
public string UserNameB { get; set; }
public string UserIDB { get; set; }
}
}
View :-
#model TestingMVC4.Models.Main
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>Main</legend>
<div class="editor-label">
#Html.LabelFor(model => model.Main1)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Main1)
#Html.ValidationMessageFor(model => model.Main1)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.Main2)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.Main2)
#Html.ValidationMessageFor(model => model.Main2)
</div>
<div>
#Html.Action("PartialA","TestPartial")
</div>
<div>
#Html.Action("PartialB","TestPartial")
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
#model TestingMVC4.Models.PartialA
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
<legend>PartialA</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.UserID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.UserID)
#Html.ValidationMessageFor(model => model.UserID)
</div>
</fieldset>
}
Mine Question is if doing like this, the Index of HTTPPOST of main view will fire first. than follow by Partial view A and Partial View B. In this case I need to store the data in HttpContext.Items and call the submit to Database in the last Partial view B.
What I want is fire the Partial view A and B first, and store the data into Main View's model and call the SubmitDatatoDB function in Main View's POST Action.
Figure out 2 method to achieve mine goal
1) Passing the main model to each partial view, sample of partial view :-
#model TestingMVC4.Models.Main
//#model TestingMVC4.Models.PartialA
<fieldset>
<legend>PartialA</legend>
<div class="editor-label">
#Html.LabelFor(model => model.PA.UserName)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PA.UserName)
#Html.ValidationMessageFor(model => model.PA.UserName)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PA.UserID)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.PA.UserID)
#Html.ValidationMessageFor(model => model.PA.UserID)
</div>
</fieldset>
disadvantages of this method is the partial view is tight to other view.
2) convert all partial view to become templates helpers :- reference from http://lostechies.com/jimmybogard/2011/09/07/building-forms-for-deep-view-model-graphs-in-asp-net-mvc/
this second method is reuse able because it used it own model binding rather than model from parent, for example :-
#model TestingMVC4.Models.ProductEditModel
#{
ViewBag.Title = "Index";
}
<p>
#Html.LabelFor(m => m.Name)
#Html.TextBoxFor(m => m.Name)
</p>
#Html.EditorFor(m => m.Price)
#model TestingMVC4.Models.PriceEditModel
<p>
#Html.LabelFor(m => m.Currency)
#Html.TextBoxFor(m => m.Currency)
</p>
<p>
#Html.LabelFor(m => m.Value)
#Html.TextBoxFor(m => m.Value)
</p>
You need to change your binds to get PartialModelA to populate MainModel and ensure that Partial View A is posting back to and action on the Main Controller
Something like this:
#using (Html.BeginForm("MainAction", "MainController")) {
<fieldset>
<legend>PartialA</legend>
<div class="editor-label">
#Html.Label("UserName", model.UserName)
</div>
<input type="submit" />
</fieldset>
}
Notice the Action and Controller added to the form and the change of LabelFor to use just Label.
I have a controller which looks like;
[HttpPost]
[Authorize(Roles = "Admin")]
public ActionResult ProjectAdd(PortfolioViewModel model, int[] categories, HttpPostedFileBase thumbnail, HttpPostedFileBase image)
{
model.ProjectImage = System.IO.Path.GetFileName(image.FileName);
model.ProjectThubmnail = System.IO.Path.GetFileName(thumbnail.FileName);
using (PortfolioManager pm = new PortfolioManager())
{
using (CategoryManager cm = new CategoryManager())
{
if (ModelState.IsValid)
{
bool status = pm.AddNewProject(model, categories);
}
ViewBag.Categories = cm.GetAllCategories();
ViewBag.ProjectsList = pm.GetAllProjects();
}
}
return View(model);
}
My View is;
#using (Html.BeginForm("projectAdd", "home", FormMethod.Post, new { enctype = "multipart/form-data" }))
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Add New Project</legend>
<div class="editor-label">
#Html.LabelFor(model => model.ProjectHeading)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ProjectHeading)
#Html.ValidationMessageFor(model => model.ProjectHeading)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ProjecctUrl)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ProjecctUrl)
#Html.ValidationMessageFor(model => model.ProjecctUrl)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.ProjectLongDescription)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.ProjectLongDescription)
#Html.ValidationMessageFor(model => model.ProjectLongDescription)
</div>
<div class="editor-label">
#Html.LabelFor(model => model.PromoFront)
</div>
#Html.EditorFor(model => model.PromoFront)
#Html.ValidationMessageFor(model => model.PromoFront)
<div class="editor-label">
<label for="thumbnail">Thumbnail</label>
</div>
<div class="editor-field">
<input type="file" name="thumbnail" id="thumbnail" />
</div>
<div class="editor-label">
<label for="image">Image</label>
</div>
<div class="editor-field">
<input type="file" name="image" id="image" />
</div>
<div class="editor-label">
<label for="categories">Categories</label>
</div>
#foreach (var c in categories)
{
<input type="checkbox" name="categories" value="#c.CategoryId">
#c.CategoryName
}
<p>
<input type="submit" value="Create" class="submit" />
</p>
</fieldset>
}
When I try this code, The ModeState.IsValid property becomes false (I saw through debugging). However, when I remove ModeState.IsValid, the insertation is done successfully and everything works exactly what I want.
I need ModeState.IsValid property for validating my view.
Updated: My viewmodel is;
[Key]
public int ProjectId { get; set; }
[Required(ErrorMessage="Please enter project heading")]
public string ProjectHeading { get; set; }
[Required(ErrorMessage = "Please enter project Url")]
public string ProjecctUrl { get; set; }
[Required(ErrorMessage = "Please enter project description")]
public string ProjectLongDescription { get; set; }
public string ProjectShortDescription
{
get
{
var text = ProjectLongDescription;
if (text.Length > ApplicationConfiguration.ProjectShortDescriptionLength)
{
text = text.Remove(ApplicationConfiguration.ProjectShortDescriptionLength);
text += "...";
}
return text;
}
}
public bool PromoFront { get; set; }
[Required(ErrorMessage = "You must sepcify a thumbnail")]
public string ProjectThubmnail { get; set; }
[Required(ErrorMessage = "You must select an image")]
public string ProjectImage { get; set; }
public int CategoryId { get; set; }
public IEnumerable<Category> Categories { get; set; }
Updated 2: I found the error. the problem is
{System.InvalidOperationException: The parameter conversion from type 'System.String' to type 'PortfolioMVC4.Models.Category' failed because no type converter can convert between these types.
at System.Web.Mvc.ValueProviderResult.ConvertSimpleType(CultureInfo culture, Object value, Type destinationType)
at System.Web.Mvc.ValueProviderResult.UnwrapPossibleArrayType(CultureInfo culture, Object value, Type destinationType)
at System.Web.Mvc.ValueProviderResult.ConvertTo(Type type, CultureInfo culture)
at System.Web.Mvc.DefaultModelBinder.ConvertProviderResult(ModelStateDictionary modelState, String modelStateKey, ValueProviderResult valueProviderResult, Type destinationType)}
When in debug, check the ModelState for errors. It's a key/value dictionary with all the properties required to make the model valid. If you check the Values-property you can find the value with the Errors-list that is not empty and see what the error is.
Or add this line of code in the action method to get all the errors for the model:
var errors = ModelState.Where(v => v.Value.Errors.Any());
You should rename your categories action parameter to something else because your PortfolioViewModel model already has a property called Categories which is of completely different type and which confuses the model binder:
[HttpPost]
[Authorize(Roles = "Admin")]
public ActionResult ProjectAdd(
PortfolioViewModel model,
int[] categoryIds,
HttpPostedFileBase thumbnail,
HttpPostedFileBase image
)
{
...
}
Now obviously you will also have to update your view to match the checkbox name.
While this might solve your issue I would very strongly recommend you using view models and stop passing your domain models to the views.