I'm beginner in C#. When I postback the form to server its show null value in model. Pls help I have no clue what to do?
Controller Code:
[HttpPost]
[ValidateAntiForgeryToken]
[Authorize(Roles = "administrator")]
public ActionResult ChangeUserDetail(ChangeUserDataModel model)
{
// ....
}
Model Code:
public class ChangeUserDataModel
{
[Display(Name = "User Name")]
public string UserName { get; set; }
[Display(Name = "Update Field")]
public string Change { get; set; }
[Required]
public string Value { get; set; }
}
View Code:
using (Html.BeginForm("ChangeUserDetail", "Home", FormMethod.Post)
{
var model2 = new Webrims.Models.AdminViewModel.ChangeUserDataModel();
<div class="form-group">
#Html.LabelFor(m => model2.UserName)
<div class="col-md-8">
#Html.DropDownListFor(m => model2.UserName, new
SelectList(ViewBag.UserNames, "Value", "Text")
</div>
</div>
.....
}
I think that this line
var model2 = new Webrims.Models.AdminViewModel.ChangeUserDataModel();
is not corrrect. Why would you need to initiate here a model?
In an MVC architecture the View receives the Model that is passed from the Controller. The View doesn't create the Model that will use later. So normally in your GET request you should pass an epmty model and on POST this model would be created based on the values that the form you POST contains.
In terms of code. The expected is something like this:
View
using (Html.BeginForm("ChangeUserDetail", "Home", FormMethod.Post)
{
<div class="form-group">
#Html.LabelFor(m => m.UserName)
<div class="col-md-8">
#Html.DropDownListFor(m => m.UserName, new
SelectList(ViewBag.UserNames, "Value", "Text")
</div>
</div>
}
Furthermore, at the top of your view you should define the type of the Model you expcet:
#model Webrims.Models.AdminViewModel.ChangeUserDataModel
Use this code in view, should work.
#model Webrims.Models.AdminViewModel.ChangeUserDataModel
using (Html.BeginForm("ChangeUserDetail", "Home", FormMethod.Post)
{
<div class="form-group">
#Html.LabelFor(m => Model.UserName)
<div class="col-md-8">
#Html.DropDownListFor(m => Model.UserName, new
SelectList(ViewBag.UserNames, "Value", "Text")
</div>
</div>
}
Related
I have absolutely no idea why my model is null when I'm trying to submit this form with only ONE field, a dropdownlistfor selected value.
The Get works just fine, and the Model is defintively not null. But everytime I try to submit the form, model is always null and I have no idea why at the moment:
Model:
[Required]
public string SelectedOrderStatus { get; set; }
public List<SelectListItem> OrderStatuses { get; set; }
View:
#model Webstore.Models.OrderViewModel
#using (Html.BeginForm("Edit", "Order", FormMethod.Post))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.OrderId)
<div class="form-horizontal">
<h4>Change Order Status for order: #Model.OrderId</h4>
<div class="form-group">
#Html.LabelFor(model => model.Orderstatus, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownListFor(model => model.SelectedOrderStatus, new SelectList(Model.OrderStatuses, "Value", "Text"))
#Html.ValidationMessageFor(model => model.SelectedOrderStatus)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save Order Status" class="btn btn-default" />
</div>
</div>
</div>
}
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
Controller
[HttpPost]
public ActionResult Edit(Guid id, OrderViewModel model)
{
try
{
Order orderToEdit = _context.Orders.Find(id);
orderToEdit.Orderstatus = (Orderstatus)Enum.Parse(typeof(Orderstatus), model.SelectedOrderStatus);
_context.Entry(orderToEdit).State = EntityState.Modified;
_context.SaveChanges();
return RedirectToAction("Index");
}
catch
{
return View();
}
}
I would appreaciate a lot if you would help me out here!
Regards!
Try to check if FormCollection collection have value which you need. So your Edit methods will looks like:
public ActionResult Edit(Guid id, FormCollection collection)
{
// rest of logic here
}
Optionally, check in Request[..], like here:
public ActionResult Edit(Guid id)
{
var value1 = Request["SelectedOrderStatus"];
}
Of course this is not as beatifull solution as it should be, but there is some problem with model blinding which I cannot resolve without rest of code.
I am learning MVC and Entity Framework, so pleas bear my questions... I am trying to create a drop down menu for a property (Enum type) for my model class SinglePest
Here is the model:
public class SinglePest
{
public int SinglePestId { get; set; }
public PestType PestType { get; set; } // here is my problem
public string Alias { get; set; }
public string TechName { get; set; }
public string Markings { get; set; }
public string SerialNumber { get; set; }
public SourceType SourceType { get; set; }
//virtual property
public Source Source { get; set; }
}
Here is PestType:
public enum PestType
{
Dog,
Cat,
Fox,
Rabbit,
Rat
}
This is the controller:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create (//(SinglePest singlepest)
[Bind(Include= "Alias, TechName, SerialNumber, PestType, Markings")] SinglePest singlepest)
{
try
{
if (ModelState.IsValid)
{
db.SinglePests.Add(singlepest);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
ModelState.AddModelError("", "Unable to save changes, try again, if problem persits contact your administrator");
}
//ViewBag.SerialNumber = new SelectList(db.Sources, "SerialNumber", "SerialNumber", singlepest.SerialNumber);
return View(singlepest);
}
And here is the View where I get the error (There is no ViewData item of type 'IEnumerable' that has the key 'PestType'.) :
<div class="editor-label">
#Html.LabelFor(model => model.PestType, "Pest Type")
</div>
<div class="editor-field">
#Html.DropDownList("PestType", String.Empty) // here is the error
#Html.ValidationMessageFor(model => model.PestType.ToString())
</div>
Now I have seen some posts about displaying enum, but I can't figure out a solution for my problem. Could please someone give me some piece of advice on how to fix it?
Thank you for your time!
You have #Html.DropDownList("PestType", String.Empty), but the second param needs to be an IEnumerable<T>. You will need the list of your pest in the model, and then use model.Pests for example where Pets is an IEnumerable.
EDIT: Based on comment...
But I want to display just the various types of pest (Dog, Cat, etc)
not all the pests that are in my database
OK, are these categorised, could you write something like (hand written so check syntax)..
var pests = (from _context.Pests.Where(p => p.CategoryId == 1) select p.PestName).ToList();
If you need to get a IEnumerable for the enum (since I'm not sure what the DB looks like), you can use...
Enum.GetValues(typeof(PestType))
.OfType<PestType>()
.Where(p => p == ??);
Currently your model only contains a place to store the value and not a Array/IEnumerable to populate the drop down from.
First add an IEnumerable to your model:
public class SinglePest
{
public int SinglePestId { get; set; }
public IEnumerable<PestType> Pests { get; set; }
public PestType PestType { get; set; }
public string Alias { get; set; }
public string TechName { get; set; }
public string Markings { get; set; }
public string SerialNumber { get; set; }
public SourceType SourceType { get; set; }
//virtual property
public Source Source { get; set; }
}
And in your controller:
public ActionResult Create()
{
var model = new SinglePest();
model.Pests = Enum.GetValues(typeof(PestType)).Cast<PestType>()
return View(model);
}
And your view:
#Html.DropDownListFor(m => m.PestType, Model.Pests);
Sorry if theres any errors I've written this from memory...
I found this post on DropDownListFor enums
It seems it is solving my problem.
so I have just changed the view with this new piece of code:
<div class="editor-label">
#Html.LabelFor(model => model.PestType, "Pest Type")
</div>
<div class="editor-field">
#Html.DropDownListFor(model => model.PestType, new SelectList(Enum.GetValues(typeof( MvcTrackingSystem.Enums.PestType))))
#Html.ValidationMessageFor(model => model.PestType)
</div>
Now it looks like it is working
On the difference between DropDownList and DropDownListFor I have found useful infromation on this post
You can fix the original problem quite simply with this in your GET Create method:
ViewBag.PestType = new SelectList(Enum.GetValues(typeof(PestType)).OfType<PestType>());
and this in your POST Create method (where validation fails and it returns the view):
ViewBag.PestType = new SelectList(Enum.GetValues(typeof(PestType)).OfType<PestType>(),
singlepest.PestType);
if you want to keep it strongly typed in the view use:
#Html.DropDownListFor(model => model.PestType, ViewBag.PestType as SelectList)
If you don't mind the weak typed version use the simpler:
#Html.DropDownList("PestType")
In either case I suggest you create all lists in the controller and not in the view.
Explanation:
Basically DropDownlist will search the ViewData (i.e. your ViewBag settings) for a list of options for the member of the same name (if a list is not explicitly provided).
I mocked up the whole project (MVC5/VS2013) and more of the code is below for your reference.
Controller:
using PestTypeTest.Models;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace PestTypeTest.Controllers
{
public class PestTypeController : Controller
{
//
// GET: /PestType/
public ActionResult Index()
{
return RedirectToAction("Create");
}
public ActionResult Create()
{
ViewBag.PestType = new SelectList(Enum.GetValues(typeof(PestType)).OfType<PestType>());
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create(//(SinglePest singlepest)
[Bind(Include = "Alias, TechName, SerialNumber, PestType, Markings")] SinglePest singlepest)
{
try
{
if (ModelState.IsValid)
{
//db.SinglePests.Add(singlepest);
//db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
ModelState.AddModelError("", "Unable to save changes, try again, if problem persits contact your administrator");
}
//ViewBag.SerialNumber = new SelectList(db.Sources, "SerialNumber", "SerialNumber", singlepest.SerialNumber);
ViewBag.PestType = new SelectList(Enum.GetValues(typeof(PestType)).OfType<PestType>(), singlepest.PestType);
return View(singlepest);
}
}
}
Views\PestType\Create.cshtml
#model PestTypeTest.Models.SinglePest
#{
ViewBag.Title = "Create";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>SinglePest</h4>
<hr />
#Html.ValidationSummary(true)
<div class="form-group">
#Html.LabelFor(model => model.PestType, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.DropDownList("PestType")
#Html.ValidationMessageFor(model => model.PestType)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Alias, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Alias)
#Html.ValidationMessageFor(model => model.Alias)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.TechName, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.TechName)
#Html.ValidationMessageFor(model => model.TechName)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Markings, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Markings)
#Html.ValidationMessageFor(model => model.Markings)
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.SerialNumber, new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.SerialNumber)
#Html.ValidationMessageFor(model => model.SerialNumber)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
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>
}
My resister works perfectly when passing back the form, but one that I built it passes back nothing. I am not sure what I am doing differently than the register page that visual studio provided. It calls the right http post method but the value passed is null. thanks for any help. I just want that model to post back to the controller action result.
Controller
[HttpGet]
public ActionResult Support()
{
ViewBag.Message = "Your app description page.";
return View();
}
[AllowAnonymous]
[HttpPost, ValidateSpamPrevention]
public ActionResult Support(QuickEmailModel email)
{
if (ModelState.IsValid)
{
return View("thankyou", email);
}
return View(email);
}
Model
public class QuickEmailModel
{
[DataType(DataType.EmailAddress)]
[EmailAddress]
public string Email { get; set; }
[Required]
public string Subject { get; set; }
[Required]
[DataType(DataType.MultilineText)]
public string Description { get; set; }
[Display(Name = "Company (Optional):")]
public string Company { get; set; }
}
}
Top of View
#using PoliteCaptcha
#model Models.QuickEmailModel
#{
ViewBag.Title = "Support";
}
Bottom where the form is
#using (Html.BeginForm())
{
#Html.ValidationSummary()
<div class="control-group">
<label class="control-label">
#Html.LabelFor(x => x.Company, "Company (Optional):", new { #class = "control-label" })</label>
<div class="controls">
#Html.TextBoxFor(x => x.Company, new { #class = "span4" })
</div>
</div>
<div class="control-group">
#Html.LabelFor(x => x.Email, "Email:", new { #class = "control-label" })
<div class="controls">
#Html.TextBoxFor(x => x.Email, new { #Class = "span4" })
</div>
</div>
<div class="control-group">
<label class="control-label">
#Html.LabelFor(x => x.Subject, "Subject:", new { #class = "control-label" })</label>
<div class="controls">
#Html.TextBoxFor(x => x.Subject, new { #class = "span4" })
</div>
</div>
<div class="control-group">
<label class="control-label">
#Html.LabelFor(x => x.Subject, "Description:", new { #class = "control-label" })</label>
<div class="controls">
#Html.TextAreaFor(x => x.Description, new { #class = "span4", #rows = "6", id = "txtDescription" })
</div>
</div>
#Html.SpamPreventionFields()
<input type="submit" class="btn btn-success" id="btnSubmit" value="Submit" style="margin-right: 15em;
float: right;" />
}
I believe the problem is that your parameter name is the same as one of your field names (email). Rename the Method parameter name to model (or something else besides email).
What I believe is happening is that the MVC model binder sees a posted value named "email" and it's trying to assign it to the parameter of the same name, but since it's not a string it can't do it. Thus it assigns a null.
Also, model binding is case insensitive, so Email and email are the same.
The problem is that the model mapper cannot map form name/value pairs from the POST request to an instance of QuickEmailModel object, and simply ignores them. Examine the POST request being sent in Firebug or other tool, what are the names of name/value pairs?
You should probably change your view like so:
#{ var email = ....; }
<label class="control-label">
#Html.LabelFor(x => email.Company, "Company (Optional):", new { #class = "control-label" })
</label>
<div class="controls">
#Html.TextBoxFor(x => email.Company, new { #class = "span4" })
</div>
because the name of your POST action param is "email". I think that this should force form param names to be "email.Company", etc. If not, try the other variant
#Html.TextBox("email.Company", model.Company)
This is the model example.cs
namespace View_Partial_Editor.Models
{
public class ExampleView
{
...
public string Field1 { get; set; }
public string Field2 { get; set; }
public string Field3 { get; set; }
public string Field4 { get; set; }
public string Field5 { get; set; }
...
}
}
I have this view example.cshtml:
#model View_Partial_Editor.Models.ExampleView
#{Html.RenderPartial("EditExample",Model);}
#Html.TextBoxFor(m => m.Field1)
Then i have this partialView EditExample.cshtml:
#model View_Partial_Editor.Models.ExampleView
#Html.HiddenFor(m => m.Field1)
#using (Ajax.BeginForm("EditExample", new AjaxOptions { InsertionMode = InsertionMode.Replace, UpdateTargetId = "partial" }))
{
<div>
#Html.EditorFor(m => m, "Editor", null)
</div>
<p>
<input id="buttona" type="submit" value="Save" />
</p>
}
I have this controller ExampleController:
namespace View_Partial_Editor.Controllers
{
public class ExampleController : Controller
{
//
// GET: /Example/
public ActionResult Example()
{
return View();
}
[HttpPost]
public ActionResult EditExample(ExampleView example)
{
example.Field1 ="7";
return View("Example", example);
}
}
}
And this is the editor that is called in the partial editor.cshtml
#model View_Partial_Editor.Models.ExampleView
<div class="editor-label">
#Html.LabelFor(m => m.Field1 )
</div>
<div class="editor-field">
#Html.EditorFor(m => m.Field1)
#Html.ValidationMessageFor(m => m.Field1)
</div>
<div class="editor-label">
#Html.LabelFor(m => m.Field2)
</div>
<div class="editor-field">
#Html.EditorFor(m => m.Field2)
#Html.ValidationMessageFor(m => m.Field2)
</div>
My problem is that i want to modify the data of the model in the controller in the ajax call, and return the model modified to the exampleView.But when the ajax called finish the value that i change in the controller is not changed in the model
Edit: The thing that i want is to send the call to the ajax methos, save something in the database, then modify the model, and in the example view i want to have that model with the changes.
In this moment, if i replace the partial view with the result of the ajax, the model in the example view is not modified.Another way is to replace the full example view, so the model is received there, but i have to pass a lot of fields using Html.HiddenFor, is possible to make this without replacing the views only returnng the model with the changes
Try calling ModelState.Clear() in your HttpPost action method. Html helpers use the values in the ModelState first, then the Model. If you change a value in the model on a post therefore, you need to clear the value from the ModelState.