Posting part of viewModel to post action method - c#

I would like to know if I am doing something wrong or it is not possible to post only part of view model using default model binder. Let's say I have a complex viewmodel that only small part it should be posted. I would like to achieve something like this:
public class ComplexViewModel
{
public object FirstNotPostedData { get; set; }
public object SecondNotPostedData { get; set; }
//......
public object NthNotPostedData { get; set; }
public InnerModelToPost InnerModelToPost { get; set; }
}
public class InnerModelToPost
{
public string FirstProperty { get; set; }
public string SecondProperty { get; set; }
public string ThirdProperty { get; set; }
}
In view I would like to display part of model and post the other part:
#model ComplexViewModel
#* DISPLAYING DATA *#
<form>
#Html.HiddenFor( m => m.InnerModelToPost.FirstProperty )
#Html.HiddenFor( m => m.InnerModelToPost.SecondProperty )
#Html.HiddenFor( m => m.InnerModelToPost.ThirdProperty )
<button type="submit">Submit button</button>
</form>
And then I would like to be able to pass this model to my controller in this way using default model binder:
public ActionResult GetOnlyImportantPartOfModel( InnerModelToPost innermodel)
{
//I'm getting empty model when I' doing like this
return View();
}
You may ask why not to pass entire model as parameter to this action method. So the answer is: code readablity. I store ComplexViewModel in session and I read it in first line of my action method. I would like to pass only this data that I want to update my model with.

Your need to use the Prefix property of [Bind] attribute to strip the InnerModelToPost prefix from your form values.
public ActionResult GetOnlyImportantPartOfModel([Bind(Prefix = "InnerModelToPost")] InnerModelToPost innermodel)
{
....
}
Having said that, if your only using properties of InnerModelToPost, then in your GET method, you can read the parent class (ComplexViewModel) from Session, but pass only the InnerModelToPost property to the view

Related

Accessing model value for if statement

I'm new to MVC and I'm trying to make an if statement in the controller that accesses a value from my model. For example, if I am trying to access this radio button value from my model, how would I do it?
[Required] public bool radbutton { get; set; }.
At the top, I tried 'using PasswordTool.Models'.
Then inside my method:
if(PasswordModel.radbutton)
//do something
PasswordModel
namespace PasswordTool.Models
{
public class PasswordModel
{
[Required] public string Password { get; set; }
[Required] public bool RadioButton { get; set; }
}
}
I expect the PasswordModel.radbutton to access the value of the radio button in the model, but intellisense isn't even registering that it exists.
Hi there heisenberg3481,
Welcome to StackOverflow!
To pass Model values from the View you would need to do the following:
#model PasswordModel
// - If the bellow doesn't work try removing the 'Controller' in "MemberController" - //
#using (Html.BeginForm("GetPassword", "MemberController"))
{
Html.TextBoxFor(x => x.Password);
Html.RadioButtonFor(x => x.RadioButton);
<button type="submit">
Submit
</button>
}
Then in your controller you can retrieve the data like so:
[HttpPost]
public ActionResult GetPassword (PasswordModel objModel)
{
if (objModel.RadioButton) {
// Execute action
}
return View();
}

What is the appropriate way of collecting data from a form that has PartialView that change based on condition

I have a ParentView that has few fields of its own. This ParentView renders a single PartialView out of 3 different PartialViews based on dropdown selected in the ParentView. So there is PartialViewA, PartialViewB and PartialViewC. At a time only one will be rendered. Each has its own Table ie. model class.
Eg: PartialViewAModel:ParentViewModel .. and so on.
One of the ways I could think of collecting data is by using FormCollection.
So if dropdownvalue is A I would know what keys I have to pick and where to store.
But is there a more elegant way for binding the data? Had there been only one view and model I could have simply used Modelclass in the binding. Eg: ublic
[HttpPost]
ActionResult Create(CustomerClass cust)
If you specify a Parent View Model that has child Partial View Models, like this:
public class ParentViewModel
{
public ParentViewModel()
{
PartialViewModel1 = new PartialViewModel1();
PartialViewModel2 = new PartialViewModel2();
PartialViewModel3 = new PartialViewModel3();
}
public string PartialViewType { get; set; } /* Value to determine which view to show */
public PartialViewModel1 PartialViewModel1 { get; set; }
public PartialViewModel2 PartialViewModel2 { get; set; }
public PartialViewModel3 PartialViewModel3 { get; set; }
}
Where the Partial View Models, for example PartialViewModel1, have the properties unique to that view model, like this:
public class PartialViewModel1
{
public string Property1_1 { get; set; }
public string Property1_2 { get; set; }
public string Property1_3 { get; set; }
}
You can specify your Parent View so that it has a form which contains the partial views, which can be toggled on the client side with a bit of JavaScript (which I haven't included but should be simple enough :) ):
#model Models.ParentViewModel
#using (Html.BeginForm("Update", "Home", FormMethod.Post))
{
#Html.TextBoxFor(x => x.PartialViewType) /* Change this to a drop down */
#Html.Partial("PartialView1")
#Html.Partial("PartialView2")
#Html.Partial("PartialView3")
<input type="submit" value="Submit" />
}
The Partial Views look like this, e.g. for PartialView1:
#model Models.ParentViewModel
<h3>Partial View 1</h3>
<p>#Html.TextBoxFor(x => x.PartialViewModel1.Property1_1)</p>
<p>#Html.TextBoxFor(x => x.PartialViewModel1.Property1_2)</p>
<p>#Html.TextBoxFor(x => x.PartialViewModel1.Property1_3)</p>
So now you can submit to the Update action on your controller by passing through the ParentViewModel:
[HttpPost]
public ActionResult Update(ParentViewModel model)
{
// Do whatever processing required.
// You can switch on model.PartialViewType to process the appropriate PartialView fields
return View("Index", model);
}
When you submit, the model should then contain whatever has been submitted in the appropriate Partial View Model properties.
Hope this helps!

How MVC creates c# class from html form?

we have some c# model
public class PartnerRegistrationForm
{
public string Name { get; set; }
public string Company { get; set; }
public string Email { get; set; }
}
class that contains this model
public class PartnerRegistrationFormHolder
{
public PartnerRegistrationForm PartnerRegistrationForm { get; set; }
}
view
#model WebApplication1.Models.PartnerRegistrationFormHolder
#using (Html.BeginForm("Index", "Registration", FormMethod.Post))
{
#Html.TextBoxFor(e => e.PartnerRegistrationForm.Name)
#Html.TextBoxFor(e => e.PartnerRegistrationForm.Email)
#Html.TextBoxFor(e => e.PartnerRegistrationForm.Company)
<button type="submit">Send</button>
}
this method TextBoxFor create inputs with long names like 'PartnerRegistrationForm.Company'
ok, its reflection magic
then i fill this form and submit it
i have view
[HttpPost]
public ActionResult Index(PartnerRegistrationFormHolder partnerRegistrationFormHolder)
{
return new HttpNotFoundResult();
}
i run my program with debug and take a breakpoint on this action
HOW MVC create object from form? can anyone explain me or give me some link where to read?
more reflection magic :) it's called model binding:
https://learn.microsoft.com/en-us/aspnet/core/mvc/models/model-binding?view=aspnetcore-2.1

#Html.DropDownList returns null when submitted

I have here a scenario. I want to make an HTTP POST action in the form so here's how I did it.
public class Item
{
public Item()
{
Storages = new HashSet<Storage>();
}
public int Id { get; set; }
public string Name { get; set; }
public virtual ICollection<Storage> Storages { get; set; }
-- remove some lines for brevity --
}
public class Storage
{
public int Id { get; set; }
public string Name { get; set; }
--- remove some lines for brevity --
}
So basically, An Item has many Storage And so I created viewmodel.
public class CreateStockViewModel
{
public string Name { get; set; }
public int StorageId { get; set; }
-- remove some lines for brevity --
}
In my Controller. I have this
[HttpGet]
public ActionResult Create()
{
ViewBag.Storages = _storageService.All
.OrderBy(i => i.Name)
.ToSelectList(s => s.Name, s => s.Id);
return View();
}
In my View:
#model Wsfis.Web.ViewModels.ItemViewModels.CreateStockViewModel
#Html.DropDownList("Storages")
Now my problem is, when I submit the form. And have Quick Watch to the model being passed. It is Null or 0
public ActionResult Create(CreateStockViewModel item)
{
// some code
}
In a nutshell,
When I submit the form all fields are being bind except for the #Html.DropDownList. Where did I missed?
Some additional side note:
They say Views should be strongly typed. Then what should I pass in View then? (A sample code would be great. Thanks)
As for the ToSelectList method I copy this code (I hope it's alright)
Any help would be much appreciated. Thanks.
Your form input has a different name to your property so the default model binder doesn't know how to bind your model.
You could pass in a different name to use to the DropDownList helper, however I prefer to use the strongly typed helpers:
#Html.DropDownListFor(m => m.StorageId, ViewBag.Storages as IEnumerable<SelectListItem>)
Try like this:
ViewBag.StorageId = _storageService.All
.OrderBy(i => i.Name)
.ToSelectList(s => s.Name, s => s.Id);
in view:
#Html.DropDownList("StorageId")
it will now post the drop down list selected value in CreateStockViewModel object's StorageId property.

Null values on model after sending model to controller

I'm using .net MVC.
I have some values in a form like:
#Html.TextBoxFor(model => model.Name, new { #class = "form-control" })
On the controller, I get the data like:
public ActionResult NovaPessoa(Person person)
{
The problem is that I just can get values that I have placed the #Html.TextBoxFor markup.
All the other complex information, like person.ContactInformation is lost after submiting and I can't use the SaveChanges in Entity Framework, because it will give me an invalid object after using the Atach method.
The question is: Do I need to use the #Html.TextBoxFor markup for all my model properties, even if I'm not using then to display anything, just to have them on Controller?
You are correct. What people (incorrectly) do normally, is use HiddenFor:
#Html.HiddenFor(model => model.ContactInformation)
What you should be doing, is cutting down your model into a view model with only the appropriate properties.
So, don't use this model:
public class PersonVM {
public int PersonId { get; set; }
public string FirstName { get; set; }
public string Surname { get; set; }
public string ContactInformation { get; set; }
}
..if all you're doing is updating the contact information. Instead, create a new class for your model:
public class PersonContactInfoEditVM {
public int PersonId { get; set; }
public string ContactInformation { get; set; }
}
That's all you need. This saves you from creating invalid objects when you don't add 30 HiddenFor elements to your page .. resulting in very broken data.
You might be thinking "ugggghhhh, all that manual mapping from PersonContactInfoEditVM to Person... I don't want to be writing that sort of code". No one does.. which is why the following libraries exist:
AutoMapper
ValueInjector

Categories