ViewModel:
public class EventViewModel
{
public Organization.Event Evt { get; set; }
public GuestContributor Gst { get; set; }
}
Through this ViewModel, I am displaying event data using Evt property which is working fine. And Gst property used to get data from a form on the same page:
#using (Html.BeginForm("GuestApplyToEvent", "Event", FormMethod.Post))
{ <div class="row">
<div class="col-12 col-md-6">
#Html.TextBoxFor(c => c.Gst.Name, new { #class = "form-control", placeholder = "Name" })
#Html.ValidationMessageFor(c => c.Gst.Name)
</div>
<div class="col-12 col-md-6">
#Html.TextBoxFor(c => c.Gst.Email, new { #class = "form-control", placeholder = "Email Address" })
#Html.ValidationMessageFor(c => c.Gst.Email)
</div>
</div>
<div class="row">
<div class="col-12 ">
#Html.TextBoxFor(c => c.Gst.Mobile, new { #class = "form-control", placeholder = "Mobile (WhatsApp Number)" })
#Html.ValidationMessageFor(c => c.Gst.Mobile)
</div>
</div>
<input type="submit" class="btn dorne-btn" value="Apply" />
}}
When sending this ViewModel to my View I am not assigning anything to Gst.
And this is the action:
[HttpPost]
public ActionResult GuestApplyToEvent(Models.GuestContributor eventViewModel)
{
if (!ModelState.IsValid)
return View("~/Views/Event/Index.cshtml", eventViewModel);
return View("~/Views/Event/Index.cshtml", eventViewModel);
}
The problem is that all the properties in eventViewModel are null even after the data is entered.
Your Post method is expecting a model of type GuestContributor but in your View it appears you are using model EventViewModel, try changing your Post Method to receive model type EventViewModel
Related
I am trying to submit a form that incorporates an #Html.EditorFor element. If I remove the EditorFor element, my POST controller argument passes data correctly, but once implemented, my entire model argument shows as null in the POST controller.
Here's the model I'm trying to pass:
public class Checkout
{
public int CheckoutID { get; set; }
public string Requestor { get; set; }
public DateTime? DateRequested { get; set; }
public List<CheckoutReceiver> Receivers { get; set; }
}
The form element on page:
#model PRI.Models.Checkout
#using (Html.BeginForm("CreateCheckout", "API/CheckoutRequest", FormMethod.Post, new { id = "pri-form" }))
{
<div id="checkout-request">
#Html.AntiForgeryToken()
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div id="checkout-info" class="form-horizontal">
<div class="form-group">
<div class="col-md-12">
#Html.TextBoxFor(m => m.CheckoutID)
</div>
</div>
<div class="form-group">
<div class="col-md-12">
#Html.EditorFor(m => m.Receivers)
</div>
</div>
<div class="form-group">
<div class="col-md-12">
<input id="create-checkout-submit" type="submit" value="Confirm transfer" class="btn btn-danger right" style="margin: 10px;" />
</div>
</div>
</div>
</div>
}
If I remove the #Html.EditorFor(m => m.Receivers), and add data to the #Html.TextBoxFor(m => m.CheckoutID) then that passes correctly to my Post Controller, so obviously my EditorFor is messing things up:
Here's the POST controller (i put a breakpoint right after it enters this so I can check the checkout argument):
[System.Web.Http.HttpPost]
[ValidateAntiForgeryToken]
[System.Web.Http.ActionName("CreateCheckout")]
public Checkout Create(Checkout checkout)
{
var request = new Checkout();
return request;
}
Here's my CheckoutReceiver Editor template (removed some input elements for brevity):
#model PRI.Models.CheckoutReceiver
#using (Html.BeginCollectionItem("Receivers"))
{
<div class="form-horizontal">
#Html.HiddenFor(model => model.ID)
#Html.HiddenFor(model => model.CheckoutID)
<h4 class="contact-header">#Model.ContactType</h4>
<div class="form-group">
<div class="col-md-5">
<span class="form-header">Last Name</span>
#Html.TextBoxFor(model => model.LastName, new { #class = "box-customer form-control ignore", placeholder = "Last name" })
</div>
<div class="col-md-5">
<span class="form-header">First Name</span>
#Html.TextBoxFor(model => model.FirstName, new { #class = "form-control ignore", placeholder = "First name" })
</div>
<div class="col-md-2">
<span class="form-header">Middle Initial</span>
#Html.TextBoxFor(model => model.MiddleInitial, new { #class = "form-control ignore", placeholder = "M.I." })
</div>
</div>
</div>
}
Where am I going wrong, and why is my EditorFor causing my Checkout POST argument to be null on submit?
Thanks!
Maybe you should check this question. You should add an editor for an
IEnumerable<CheckoutReceiver> instead of an editor for CheckoutReceiver.
This question already has answers here:
Asp.Net MVC: Why is my view passing NULL models back to my controller?
(2 answers)
Closed 5 years ago.
I'm trying to send a form to ActionResult method but it is null always. In fact, I got the error Value cannot be null. but I don't know why I got it the error.
Here is ActionResult code and my view.
public class VocabularyController : Controller
{
private VocabContext _context;
public VocabularyController()
{
_context = new VocabContext();
}
// GET: Vocabulary
[Route("New")]
public ActionResult New()
{
return View();
}
[HttpPost]
public ActionResult Save(Vocabulary word)
{
if (ModelState.IsValid)
{
_context.Vocabularies.Add(word);
_context.SaveChanges();
}
return RedirectToAction("dashboard", "Home");
}
}
==============================
#model EnglishTest.Models.Vocabulary
#{
ViewBag.Title = "New";
}
<div class="row">
<div class="col-lg-12">
<div class="element-wrapper">
<h6 class="element-header">New Word Form</h6>
<div class="element-box">
#using (Html.BeginForm("Save", "Vocabulary", FormMethod.Post))
{
<div class="form-group">
#Html.LabelFor(m => m.Word)
#Html.TextAreaFor(m => m.Word, new { #class = "form-control", #placeholder = "Word" })
#Html.ValidationMessageFor(m => m.Word)
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
#Html.LabelFor(m => m.Defination)
#Html.TextAreaFor(m => m.Defination, new { #class = "form-control", #placeholder = "Definition" })
#Html.ValidationMessageFor(m => m.Defination)
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
#Html.LabelFor(m => m.Synonym)
#Html.TextAreaFor(m => m.Synonym, new { #class = "form-control", #placeholder = "Synonym" })
#Html.ValidationMessageFor(m => m.Synonym)
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
#Html.LabelFor(m => m.PersianTranslate)
#Html.TextAreaFor(m => m.PersianTranslate, new { #class = "form-control", #placeholder = "Persian Translation" })
#Html.ValidationMessageFor(m => m.PersianTranslate)
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div class="form-group">
#Html.LabelFor(m => m.Examples)
#Html.TextAreaFor(m => m.Examples, new { #class = "form-control", #placeholder = "Examples" })
#Html.ValidationMessageFor(m => m.Examples)
</div>
</div>
</div>
#Html.HiddenFor(m => m.Id)
<div class="form-buttons-w"><button class="btn btn-primary" type="submit"> Save</button></div>
}
</div>
</div>
</div>
</div></div>
==============================
public class Vocabulary
{
public int Id { get; set; }
[Required]
public string Word { get; set; }
[Required]
public string Defination { get; set; }
[Required]
public string Synonym { get; set; }
[Required]
public string PersianTranslate { get; set; }
[Required]
public string Examples { get; set; }
}
I Changed the input parameter to my model name, it works fine.
public ActionResult Save(Vocabulary vocabulary)
Specify a post to the form:
#using (Html.BeginForm("Save", "Vocabulary", FormMethod.Post))
Also the second # is not requried:
Html.BeginForm("Save", "Vocabulary", FormMethod.Post)
I've come up with problem, when trying to fill data to my model. I have an "Resource" entity, which can have no-to-many "attributes". I have templates set up, which holds names for those attributes. When Resource is created, user chooses on of templates, then Attributes are created(empty) and program generates form for those attributes.
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(Model => Model.Resource)
#for (int i = 0; i < Model.Attributes.Count(); i++)
{
<div class="form-group">
#*Html.LabelFor(d => d.Attributes.ToArray()[i].Name, htmlAttributes: new { #class = "control-label col-md-2" })*#
<h4>#Html.Raw(Model.Attributes.ToList()[i].Name)</h4>
<div class="col-md-10">
#Html.TextBoxFor(Model => Model.Attributes.ToList()[i].Value, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(Model => Model.Attributes.ToList()[i].Value, "", new { #class = "text-danger" })
</div>
</div>
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
This form uses this View model:
public class ResourceAttributesViewModel
{
public virtual Resource Resource { get; set; }
public virtual ICollection<_Attribute> Attributes { get; set; }
}
problem is that when i hit "submit" button, it gives me view model with null Resource and Attributes properties
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Fill(ResourceAttributesViewModel AttributeSet)
{
if(ModelState.IsValid)
{
foreach (var attr in AttributeSet.Attributes)
{
db.Entry(attr).State = EntityState.Modified;
db.SaveChanges();
}
return RedirectToAction("Index");
}
return View(AttributeSet);
}
if it helps, there is POST string sent by browser
__RequestVerificationToken=XoVM9h_3njX5x2m35b_vKKHY3m5UDaYm9_2ZMfNkglouqHJCSw2NO56Tv2Sb3kXy8qC8XBLXawoQv0ft0xc-LxYmQGfi4EAqroq2b63Wb9Q1&Resource=System.Data.Entity.DynamicProxies.Resource_7639327FA0332BEBC7FB6836F70C3D62C3D744D76F2C3F8DDFCE679AA8CA31DC&%5B0%5D.Value=100&%5B1%5D.Value=200
I am redirecting my viewModel from the HttpPost of View1 to the HttpGet of View2.
This works without problems.
There the user has to accept the terms and agreemens.
This should get changed in the viewModel to true (before it is false).
And then redirect to the HttpPost of view2.
There something goes wrong.
The HttpPost ActionResult of View2 receives the viewModel with all Parameters as NULL (before they were filled)
How can I fix this?
Here is my HttpGet ActionResult for View2:
public ActionResult Verify(QuestionViewModel viewModel)
{
//Anrede in Viewbag
if (viewModelVeri.Per_Salutation == 2)
{
ViewBag.Per_Salutation = "Frau";
}
else
{
ViewBag.Per_Salutation = "Herr";
}
int? per_region_id = viewModelVeri.Per_Region;
int per_region_id_nullable = Convert.ToInt32(per_region_id);
Region region = _repository.GetRegionById(per_region_id_nullable);
QuestionViewModel viewModel2 = new QuestionViewModel()
{
Reg_Name = region.Reg_Name
};
//Regionsname in Viewbag
ViewBag.Reg_Name = viewModel2.Reg_Name;
return View(viewModel);
}
And here's my HttpPost ActionResult for View2:
[HttpPost]
public ActionResult Verify(QuestionViewModel viewModel, string tbButton)
{
//here the ViewModel-Parameters are already NULL
My View:
<div class="panel-body">
#using (Html.BeginForm("Verify", "QuestionForm", FormMethod.Post, new { id = "verifyform" }))
{
#Html.AntiForgeryToken()
<div class="ctrl-row">
<div class="form-group">
<div class="container-fluid">
#Html.LabelFor(model => model.Per_Salutation, new { #class = "control-label col-sm-1" })
<div class="col-sm-3">
#ViewBag.Per_Salutation
</div>
</div>
</div>
</div>
<div class="ctrl-row">
<div class="form-group">
<div class="container-fluid">
#Html.LabelFor(model => model.Per_Name_Last, new { #class = "control-label col-sm-1" })
<div class="col-sm-3">
#Html.DisplayFor(model => model.Per_Name_Last, new { #class = "control-label col-sm-1 non-zero-num" })
</div>
#Html.LabelFor(model => model.Per_Name_First, new { #class = "control-label col-sm-1" })
<div class="col-sm-3">
#Html.DisplayFor(model => model.Per_Name_First, new { #class = "control-label col-sm-1 non-zero-num" })
</div>
</div>
</div>
</div
<div class="ctrl-row">
<div class="form-group">
<div class="container-fluid">
#Html.LabelFor(model => model.Per_EMail, new { #class = "control-label col-sm-1" })
<div class="col-sm-8">
#Html.DisplayFor(model => model.Per_EMail, new { #class = "control-label col-sm-1 non-zero-num" })
</div>
</div>
</div>
</div>
<div class="checkbox">
<input type="checkbox" id="NutzungsbedingungenAngenommen " />
<label for="NutzungsbedingungenAngenommen ">
Ich erkläre mich mit den Nutzungsbedingungen einverstanden.
</label>
</div>
<button class="btn btn-default" type="submit" name="tbButton" value="questsend">Senden</button>
}
<script>
$(document).ready(function () {
$(".non-zero-num").val($(this).val() == 0 ? ' ' : $(this).val());
})
$('#verifyform').on('click', '[value="questsend"]', function () {
if ($('#agree').is(':checked')) {
return true;
}
else {
return false;
}
});
</script>
EDIT
Here my QuestionViewModel
public class QuestionViewModel
{
//Other Properties
[Required(ErrorMessage = "Bitte die Nutzungsbedingungen annehmen!")]
public bool NutzungsbedingungenAngenommen { get; set; }
}
My HttpPost Controller for View1:
[HttpPost]
public ActionResult DefaultForm(QuestionViewModel viewModel, string tbButton)
{
if (ModelState.IsValid)
{
try
{
if (tbButton.Equals("questsend"))
{
return RedirectToAction("Verify", viewModel);
}
else if (tbButton.Equals("questupload"))
{
//write to DB
return View(viewModel);
}
else
{
dropdownPopulate(viewModel);
return View("DefaultForm", viewModel);
}
}
catch
{
dropdownPopulate(viewModel);
return View(viewModel);
}
}
else
{
dropdownPopulate(viewModel);
return View(viewModel);
}
}
The problem is you use Html.DisplayFor to display the property values of viewModel in View2, so the values won't be submitted to the HttpPost method, hence viewModel is null when HttpPost for View2 is executed. Only values in <input>, <textarea> and <select> tags will be submitted.
You can submit the values of viewModel to the HttpPost for View2 by adding Html.HiddenFor inside Html.BeginForm for all properties of viewModel. You should also use Html.CheckBoxFor(m => m.NutzungsbedingungenAngenommen) for the checkbox. Something like below should work
#using (Html.BeginForm("Verify", "QuestionForm", FormMethod.Post, new { id = "verifyform" }))
{
#Html.AntiForgeryToken()
#Html.HiddenFor(m => m.Per_Salutation)
#Html.HiddenFor(m => m.Per_Name_First)
#Html.HiddenFor(m => m.Per_Name_Last)
.... // Html.HiddenFor for the rest of QuestionViewModel properties
....
.... // the rest of your code inside the form tag
.... // remove <input type="checkbox" id="NutzungsbedingungenAngenommen " />
#Html.CheckBoxFor(m => m.NutzungsbedingungenAngenommen)
<button class="btn btn-default" type="submit" name="tbButton" value="questsend">Senden</button>
}
Make sure you declare what model should be used by Razor.
#model QuestionViewModel
Make sure the name and id of your HTML inputs are in the format expected by the MVC modelbinder. I recommend using the provided HtmlHelpers instead of writing the input tags by hand.
#Html.CheckBoxFor(m => m.Agree)
Remove the string tbButton parameter from your POST action
I have a model that contains a class like Days where Days are a collection of Day.
This is what the entity framework autogenerated model looks like:
public MyModel()
{
this.ExceptionDays = new HashSet<ExceptionDay>();
this.RegularDays = new HashSet<RegularDay>();
}
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public virtual ICollection<ExceptionDay> ExceptionDays { get; set; }
public virtual ICollection<RegularDay> RegularDays { get; set; }
}
The RegularDay & ExceptionDay are, both, separate classes in separate files under the autogenerated model.
Now, the create form for this model needs to take a Day and add it to the list Days. I figured I'd use a display template for doing this.
This is what my create display view looks like:
#model MyModel
#{
ViewBag.Title = "Create";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Create</h2>
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
<hr />
<div class="form-group">
<div class="col-md-10">
**#Html.EditorFor(model => model.RegularDays, "ICollection_RegularDay_Edit")**
</div>
</div>
<div class="form-group">
<div class="col-md-10">
**#Html.EditorFor(model => model.ExceptionDays, "ICollection_ExceptionDay_Edit")**
</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>
}
My Edit template looks like this:
#model RegularDay
<div class="form-group">
#Html.LabelFor(model => model.dayOfWeek)
<div class="col-md-">
<div class="col-md-">
#Html.DropDownListFor(model => model.dayOfWeek, new SelectList(
new List<Object>
{
"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"
}
))
</div>
#Html.ValidationMessageFor(model => model.dayOfWeek, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.startTime)
<div class="col-md-">
#Html.EditorFor(model => model.startTime, new { htmlAttributes = new { #class = "form-control" } })
#*#Html.ValidationMessageFor(model => model.startTime, "", new { #class = "text-danger" })*#
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.NumberOfHours)
<div class="col-md-">
#Html.DropDownListFor(model => model.NumberOfHours, new SelectList(
new List<Object>
{
1,2,3,4,5,6,7,8
}
))
</div>
</div>
The other display template for edit is similar.
Now the problem is, that my controller never gets the regularDay or ExceptionDay in the model that the view returns on post.
My controller method looks like this:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "Id,Name,Description, RegularDays, ExceptionDays")] MyModel myModel)
{
if (ModelState.IsValid)
{
db.LocationHoursModels.Add(locationHoursModel);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(myModel);
}
How can I go about creating a display template or a create view for the Days type of attribute for this MVC?