BeginForm dont sent model to Controller method POST why? - c#

I have problem i dont now how to fix it.
I have ViewModel
public class CartOrderViewModel
{
public Cart Carts;
public Order Orders;
public string name;
}
in CartController method
public async Task<IActionResult> Index()
{
CartOrderViewModel vm = new CartOrderViewModel
{
Carts = _cart,
Orders = new Order() { User = applicationUser },
};
return View(vm);
}
View Index from CartController
#using (Html.BeginForm("Test", "Cart", FormMethod.Post))
{
#Html.TextBoxFor(m => m.name)
<input type="submit" value="Submit" />
}
and in my method Test in CartController i dont see ViewModel CartOrderViewModel
[HttpPost]
public IActionResult Test(CartOrderViewModel test)
{
string komentarz = test.name;
return View();
}
Model: test in null.
Please help me. Thx a lot
How to send form from Index View from CartController my ViewModel CartOrderViewModel
example Model.Order.name ??
Why my name from CartOrderViewModel dont sent to method Test from index View ?
printscreen
enter image description here

Why my name from CartOrderViewModel dont sent to method Test from index View ?
ASP.NET binds to properties, not fields. Change all of the public fields in class CartOrderViewModel to be mutable properties with { get; set; }.
Like so:
public class CartOrderViewModel
{
public Cart? Carts { get; set; }
public Order? Orders { get; set; }
public String? Name { get; set; }
}
Don't forget to add validation attributes, such as [Required], as per your project's needs.

Related

C# - Passing view model data around

I have a post method that has my view model and all of its data
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SpecialOrderSelection(JobOrder job, ItemViewModel model)
{
return RedirectToAction("SpecialOrderSummary", "JODetails", model);
}
The 'special order selection' page is where a user is shown a list of parts and must choose if the part should be transferred, harvested, or disposed of. It returns the correct data to the controller. But after the submit happens I want to give the user a summary page of everything that they have done. To do this I tried passing the view model to a 'Order summary' page. With the get method looking like this
public ActionResult SpecialOrderSummary(ItemViewModel model)
{
return View(model);
}
Here is my Model
public class ItemViewModel
{
[Required]
public int ID { get; set; }
public string ItemId { get; set; }
public string ItemName { get; set; }
public string MFGNumber { get; set; }
public IList<ItemPartViewModel> Parts { get; set; }
public IList<ItemComponentViewModel> Components{ get; set; }
public IList<ComponentPartViewModel> ComponentParts { get; set; }
public IList<ComponentSubCompViewModel> ComponentSubComps { get; set; }
public IList<SubCompPartViewModel> SubCompParts { get; set; }
public IList<SubCompSubCompViewModel> SubCompSubComps { get; set; }
public IList<SubCompSubCompPartViewModel> SubCompSubCompParts { get; set; }
}
And then I want the view to do something like this
#model PIC_Program_1._0.Models.ItemViewModel
#using PIC_Program_1._0.Models
#{
ViewBag.Title = "SpecialOrderSummary";
}
#using (Html.BeginForm())
{
#Html.AntiForgeryToken()
#*#Html.HiddenFor(model => model.ID)*#
#Html.HiddenFor(x => x.ID)
<h2>Special Order Summary</h2>
<p style="color:red" class="noprint">Please review and verify </p>
<h2>
Transfers
</h2>
<h3>
Parts
</h3>
foreach (var part in Model.Parts) // part is null here
{
<p>#part.PartName</p>
}
}
But Model.Parts always has a count of 0. So I'm wondering how I can pass the data of a view model around.
Any help is appreciated.
As David suggested, I tried doing it through AJAX but it won't go to the view page that I want it to go to, just reloads the same page. Here is my AJAX method
$(document).ready(function () {
$("button").click(function () {
$.ajax({
url: '#IGT.baseUrl/JODetails/SpecialOrderSummary',
data: $('#form').serialize(),
type: 'GET'
});
});
});
I am assuming that the client passes job and model in the request body.
I'll show what happens with this sequence: https://swimlanes.io/#pZLBbhNBDIbv+xRWLgUpTQq9rUQPBKjgkopEQj06u25notlxGHuT5u3xzCQpSHDitDP2rP35969eA7WwGFOiqPCRHO49j6lpmkXwOXR9BytKe0otONVdO5/3PKCPs46H+ZZ7UvRB5rKjzmPg1FMSCtSp59g0kZXaRp0XSPRzJFE4+BDA2hD4CDmx4f4I6gi2vAGMfTkPVjnMYJ2PpI574Cf4o44dH5artZFWvkxamVv4Tr1PxgDKgAUFvi0/VdQFR00cAqXZqkIvM/RqHAZMR7ggE/Bmm2tMCssEjjwCJoIdivj4DI7s0jNJvFL7wsGhlkf0YnV11mR4qWyJZMdR8j0Wqly/qwo7FOisBdzevCvzo+lCaEwwCdxhxm//JXWl/q9tnUvUwX84ioBntjf3zM+BYOESDzSFLybrE79M4YFFB4xT+BqFh+gROBUFyJq/tXk78nuSMouBgCjqKGVEe3h7874oZ2k2JdJlqSdlTC4zYVe1pj47JYfPapzkyfZ4NcSVnJ1iMQwHPArcf17XNZzGsYw1vGzwN6M9Wr+zVf5mi1fXlh8+xDGEpvkF
You just don't have to redirect the client, simply return the oter action's result:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult SpecialOrderSelection(JobOrder job, ItemViewModel model)
{
return SpecialOrderSummary(model);
}

CheckBoxFor resetting the model to null in Razor

I'm iterating a list to set the values for multiple Html.CheckBoxFor controls, but after submitting the form, I get a null value for the model itself in the controller parameter. Should I replace Html.CheckBoxFor with Html.HiddenFor for instance, the whole model binding works and FunctionViewModel is passed to the controller properly.
Model
public class FunctionViewModel
{
//... (this class is huge)
public MeasuringViewModel MeasuringViewModel { get; set; }
}
Classes used by the model
public class MeasuringViewModel
{
//... (this class is also huge)
public List<BatchItem> BatchToCancel { get; set; }
}
public class BatchItem
{
public bool IsCancel { get; set; }
public VMeasuringService VMeasuringService { get; set; }
public BatchItem(VMeasuringService vMeasuringService)
{
IsCancel = false;
VMeasuringService = vMeasuringService;
}
}
Controller
[HttpPost]
public ActionResult CancelBatch(FunctionViewModel viewModel)
{
// viewModel is null should I use CheckBoxFor
return View();
}
Form
#using (Html.BeginForm("CancelBatch", "Services", FormMethod.Post, new { Area = "Functions", #id = "cancelForm" }))
{
for(int i = 0; i < Model.MeasuringViewModel.BatchToCancel.Count; i++)
{
#Html.CheckBoxFor(m => m.MeasuringViewModel.BatchToCancel[i].IsCancel)
}
<input type="submit" id="btSubmit" title="Post" alt="Post" value="Post" />
}
So, what's wrong with it?
You get null because none of the control ids matching with your model properties, Check by Inspecting your html in browser that, is control ids generated by Razor are matching with your model properties?
secondly in this situation where you cannot give specific ids to your controls then you can get your control value in your controller action using FormCollection like given bellow:
[HttpPost]
public ActionResult CancelBatch(FormCollection fc)
{
// viewModel is null should I use CheckBoxFor
return View();
}

Pass parameter from Htmldropdownlistfor to controller

I have a model passed from controller to view in my asp.net mvc5 website. Then I show the dropdownlist using the model and I want to pass an id back when submitting the form. Here is my model :
public class SiteDirectionModel
{
public int id { get; set; }
public string name { get; set; }
}
Then in the model, I use a List<SiteDirectionModel> to which I add new instances of each item I need. I fill up both these lists and then pass my model to the view.
#model List<SiteDirectionModel>
#using (Html.BeginForm("GetSiteRF", "Create", FormMethod.Post))
{
#Html.DropDownListFor(x => x.name,new SelectList(Model.name,"Sites"));
<input type="button" value="Selectionner" class="btn btn-primary"/>
}
Then how to retrieve the ids for each name ? And how to pass it as a parameter to my controller? Such that I would have :
public ActionResult GetSiteRF(int id)
{
int newId = id;
//Call method to searchId ...
return View("CreateADUser");
}
I have given how to bind and get value from dropdown. Please use your own BL in this.
Your model should be like this.
public class Something
{
public int Id { get; set; }
public string Name { get; set; }
}
public class SiteDirectionModel
{
public SelectList MyDropDown { get; set; }
public int SelectedValue { get; set; }
}
You BL should be like this.
public List<Something> GetListofSomething()
{
//your logic.
}
Your Get method should be like this.
public ActionResult MyGetMethod()
{
SiteDirectionModel model = new SiteDirectionModel();
model.MyDropDown = new SelectList(GetListofSomething(), "key_field_name", "value_field_name", "default_value");
}
Then finally HTML
#Html.DropDownListFor(x => x.SelectedValue,Model.MyDropDown)

NullReferenceException when trying to pass a nested ViewModel to a Partial

My login and signup forms are in the same page, and they are separated by a tab element.
Each one of the forms have a ViewModel:
public class RegisterViewModel
{
public string FullName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
public class LoginViewModel
{
public string Email { get; set; }
public string Password { get; set; }
}
And since both forms are on the same page, I have a parent ViewModel:
public class LoginAndRegisterViewModel
{
public LoginViewModel LoginViewModel{ get; set; }
public RegisterViewModel RegisterViewModel{ get; set; }
}
// Actions...
public ActionResult Register()
{
return View("Login");
}
public async Task<ActionResult> Register(LoginAndRegisterViewModel model)
{
// blah.. do stuff here...
return View("Login", model);
}
But in the main view when I try to render the partials with the forms I get a System.NullReferenceException (Additional information: Object reference not set to an instance of an object.) in Model.LoginViewModel and Model.RegisterViewModel. This is the view:
Login.cshtml:
#model Models.LoginAndRegisterViewModel
...
#Html.Partial("_LoginPartial", Model.LoginViewModel)
...
#Html.Partial("_RegisterPartial", Model.RegisterViewModel)
I have seen that it is common practice to follow this kind of convention, as detailed here in this SO question. I even tried using this PartialOrNull helper but I still get the exception. I also tried the solution based on this "Forms for Deep View Model graphs" article.
Also this didn't work:
#Html.Partial("_LoginPartial", Model.LoginViewModel, new ViewDataDictionary(ViewData){Model = null});
How can I have a register/login form like this? As I said this is EXACTLY the same situation in that other SO question, and everyone reported that the solution worked, but that was for MVC3.
EDIT 1: added the _LoginPartial as reference.
#model Models.LoginViewModel
#{
using (Html.BeginForm("Login", "Account", new {ReturnUrl = ViewBag.ReturnUrl}, FormMethod.Post))
{
#Html.TextBoxFor(m => m.Email)
#Html.PasswordFor(m => m.Password)
}
}
EDIT 2: tried the ?? operator and still getting the Exception.
#Html.Partial("_LoginPartial", Model.LoginViewModel ?? new LoginViewModel())
UPDATE: With the accepted answer I made some tests and now it is working without an initialization ViewModel constructor and without sending an empty ViewModel in the Get action.
The only needed requirement is to declare the partial view to have the main model as the #model:
#model Models.LoginAndRegisterViewModel
Then to access the nested ViewModel in the partial:
#model Models.LoginAndRegisterViewModel
#{
using (Html.BeginForm("Login", "Account", new {ReturnUrl = ViewBag.ReturnUrl}, FormMethod.Post))
{
#Html.TextBoxFor(m => m.LoginViewModel.Email)
#Html.PasswordFor(m => m.LoginViewModel.Password)
}
}
You should initialize properties LoginViewModel and RegisterViewModel in the view models constructor
public class LoginAndRegisterViewModel
{
public LoginAndRegisterViewModel()
{
LoginViewModel = new LoginViewModel();
RegisterViewModel = new RegisterViewModel ();
}
public LoginViewModel LoginViewModel{ get; set; }
public RegisterViewModel RegisterViewModel{ get; set; }
}
and in the GET method, pass a new instance of the view model
public ActionResult Register()
{
var model = new LoginAndRegisterViewModel();
return View("Login", model);
}
and to ensure you model properties post back, pass the model to the partials
#Html.Partial("_LoginPartial", Model)
and change the partial to use LoginAndRegisterViewModel
#model Models.LoginAndRegisterViewModel
#using (Html.BeginForm("Login", "Account", new {ReturnUrl = ViewBag.ReturnUrl}, FormMethod.Post))
{
#Html.TextBoxFor(m => m.LoginViewModel.Email)
#Html.PasswordFor(m => m.LoginViewModel.Password)
}
This ensures the that the controls are bound to the view model and generate the correct name attributes
<input type="text: name="LoginViewModel.Email"..>
whereas passing on a property of the model would have generated
<input type="text: name="Email"..>
which would not bind to LoginAndRegisterViewModel on post back and all properties would have been null

PartialView model is empty returns null reference

I'm rendering a PartialView via an Action on my controller.
This is sending a model to the partial which then populates a sub-list for each parent that the partial goes into.
Some of the parent objects don't have children.
I need to capture an Id from the model in the partial to link the sub-list into an Accordion control.
How do I prevent a null reference exception when the child model is empty?
Is there any way to send the ID direct from the Action?
Current attempt...
#using BootstrapSupport
#model IEnumerable<WhatWorks.ViewModels.FamilyListViewModel>
#{ if (string.IsNullOrEmpty(Model.FirstOrDefault().familyId.ToString()))
{
do something...
}
else
{
int modelIndex = Model.FirstOrDefault().familyId;
Controller Action
public ActionResult Index(int Id)
{
var model = GetDisplay(Id).OrderBy(i => i.dob).AsEnumerable();
return PartialView("_family", model);
}
Main View
var family = model.GetIdValue();
<div class="accordion" id="#Html.Raw("accordion")#family.Values.FirstOrDefault()#Html.Raw("_b")">
#Html.Action("Index", "Family", new { Id = family["Id"] })
</div>
ViewModel
public partial class FamilyListViewModel
{
public int Id { get; set; }
public int familyId { get; set; }
public string name { get; set; }
etc...
}
Then do this :
#{ if (Model.Count() >0 )
{
do something...
}

Categories

Resources