ASP.NET MVC4 One View Multiple Model - c#

I've the following class structure.
public BaseClass
{
public int Id { get; set; }
public string Name { get; set; }
}
public ClassOne : BaseClass
{
}
public ClassTwo : BaseClass
{
}
My Controller is like this
public TestController : Controller
{
public ActionResult ClassOne()
{
ClassOne model = new ClassOne();
return View("Create",model);
}
public ActionResult ClassTwo()
{
ClassTwo model = new ClassTwo();
return View("Create",model);
}
My View ("Create") is like this :
#model MvcApplication.Models.BaseClass
#using(Html.BeginForm("Post","Test",FormMethod.Post))
{
#Html.HiddenFor(model => mode.Id)
#Html.TextBoxFor(model => model.Name)
<input type="submit" value="Submit"/>
}
My Post Action is the same for both the models i.e. ClassOne & ClassTwo.
On Post how can I know which model is passed in the Post Action whether it is ClassOne or ClassTwo.
[HttpPost]
public ActionResult Post(BaseClass model)
{
/* Code */
}

Inside the post just check the type. Either by if(model is ClassOne) or if(model.GetType() == typeof(ClassOne))

I'm not sure that it is possible without creating your own ModelBinder. In this case you'll always get in your action instance of BaseType class.

You can use typeof():
if(model.GetType() == typeof(ClassOne)){
// do something
}else {
// do something else.
}
Edit:
thanks to #JoreanVannevel
if(model is ClassOne){}

You can just check the type of the object.
if(model.GetType() == typeof(ClassOne))
{
// Do something
}

Jonah,
You should use one model for a view. Now you can do two things
First thing,
you can use custom model binder see here http://www.codeproject.com/Articles/605595/ASP-NET-MVC-Custom-Model-Binder
or (Second thing),
in Html.Beginform also place hidden field to for identifying type (like 1 for ClassOne , 2 for ClassTwo). and now create a third class which has distinct property of both ClassTwo and ClassOne , common property of BaseClass and a extra property for type information.(do not use any type of validation here)
for the post use the newly created type, then check the type field.

your problem is action can't judge which type.because view to action the type is loose.
but we can get type at view and send the type to the action.
view like this:
#model MvcApplication.Models.BaseClass
#using(Html.BeginForm("Post","Test",FormMethod.Post))
{
#Html.HiddenFor(model => mode.Id)
#Html.TextBoxFor(model => model.Name)
#Html.Hidden("type", model.GetType().Tostring())
<input type="submit" value="Submit"/>
}
action like this:
[HttpPost]
public ActionResult Post(BaseClass model)
{
/* Code */
if(Request["type"] == typeof( ClassOne).Tostring())
{
}
if(Request["type"] == typeof( ClassTwo ).Tostring())
{
}
}

Related

better way concept to use a Model with inheritance in a form with MVC

I want best technique in architecture MVC, to operate with a child class, I try not use more parameters, only a model, i cant use interface:
Model - parent example:
public class Animal
{
public string Name { get; set; }
public string Color { get; set; }
}
Model - child example:
public class Dog : Animal
{
public String Hair {get;set;}
}
View Sender example SenderDog.cshtml:
#model WebAppHerencia.Models.Dog
#using (Html.BeginForm())
{
#Html.LabelForModel()
#Html.LabelFor(m=>m.Name)
#Html.TextBoxFor(m => m.Name)
#Html.LabelFor(m => m.Hair)
#Html.TextBoxFor(m => m.Hair)
<input name="submitSend" type="submit" value="send"/>
}
View Receibe Example ReceiveDog.cshtml:
#model WebAppHerencia.Models.Dog
<h2>Receive Dog</h2>
#Html.LabelForModel()
#Html.LabelFor(m=>m.Hair)
#Html.EditorFor(m=>m.Hair)
The problem: Controller
public ActionResult SendDog(Animal model)
{
if (Request.Form["submitSend"]!=null)
{
var p = model as Dog;
return RedirectToAction("ReceiveDog",p);
}
return View();
}
public ActionResult ReceiveDog(Dog perro)
{
return View(perro);
}
I try send model of type Dog in Action of controller (SendDog(Animal a)) wait a Animal (parent), i know that cant pass exactly a child of this way, but I do not know how to do it in the best way... and not use another param..
debug
my scaffolding example
scaffolding

pass key value pair to controller

I've seen a couple possible solutions but they look very messy to me. Does anyone have a simple solution for this?
Model:
public class MyClass
{
public KeyValuePair<int,string> Field { get; set; }
}
Get method in controller:
public ActionResult Index()
{
var model = new MyClass();
model.Field = new KeyValuePair<int, string>(1, "test");
return View(model);
}
View:
#model WebApplication1.Models.MyClass
#using (Html.BeginForm("MyMethod", "Home", FormMethod.Post))
{
#Html.Hidden("Field", Model.Field);
<input type="submit" value="Submit" />
}
Post method in controller:
public ActionResult MyMethod(MyClass input)
{
var x = input.Field;
....
}
The Key Value pair is not passed with this method as it just comes up empty. What would be the easiest way of getting 'Field' passed to the controller?
Replace following line and try it.let me know any problem.
#Html.Hidden("Field", Model.Field);
TO
#Html.HiddenFor(m => m.Field);
If memory serves correctly, it has a Key and Value property, which like any other object would be bound like:
#Html.HiddenFor(m => m.Field.Key)
#Html.HiddenFor(m => m.Field.Value)
One input field can't represent the key and value in this way, unless you look at using a Custom Model Binder to manage the value posted back, and a Display/Editor template to render the input in a way the model binder will understand.
Following Brians answer, I've had to accept I must do it like this:
Class:
public class MyClass
{
public KeyValuePair<int,string> Field { get; set; }
public string FieldKey { get; set; }
public string FieldValue { get; set; }
}
View:
#Html.Hidden("FieldKey",Model.Field.Key)
#Html.Hidden("FieldValue", Model.Field.Value)
It will get messy as I have many of these kvp's I'd like to pass back to the controller, but I guess it's the only uncomplicated way. It's not the first time I've wished it was possible to pass objects to a controller, and I'm sure it won't be the last. Maybe we'll get the happy news in a dotnet update one day that we can do things like this more easily.

ASP.NET form submit part of a model

This is just something that has been puzzling me, I'm wondering if there's a built in way for this.
Say you have a Package class
public class Package
{
public A AObject { get; set; }
public B BObject { get; set; }
}
And you have a view that uses this Package.
public ActionResult Action()
{
return View(new Package());
}
Now the view will accept this model and have 2 forms.
#model Path.To.Package
#Html.BeginForm("SubmitA", "MyController")
{
#Html.TextBoxFor(m => m.AObject.SomeProperty);
<input type="submit" />
}
#Html.BeginForm("SubmitB", "MyController")
{
#Html.TextBoxFor(m => m.BObject.AnotherProperty);
<input type="submit" />
}
If one would create two actions needed above that take Package as argument, this would work without question...
public JsonResult SubmitA(Package items) { ... }
public JsonResult SubmitB(Package items) { ... }
But at SubmitA the BObject would be null and in SubmitB AObject would be null.
My question here is whether you can submit only a part of the model? So the first form would only submit AObject and the second BObject so you could actually reach these via the following actions:
public JsonResult SubmitA (A a) { ... }
public JsonResult SubmitB (B b) { ... }
You can use the Prefix property of BindAttribute to bind to complex properties of a model. The attribute effectively removes the prefix from the submitted name/value pairs when binding to model.
Your controller methods would be
public JsonResult SubmitA([Bind(Prefix = "AObject")]A model) { ... }
public JsonResult SubmitB([Bind(Prefix = "BObject")]B model) { ... }
You should really use separate view model for each form. You can of course, use bind attribute or use specific property names in the controller action. But, that doesn't solve your real problem. You can only get either of the values and the other object will be unassigned or NULL. This is why you should have separate view model for each view / form. You can build your Package object once you have values for both objects.

Default constructor being called during POST and I lose all model data

I am having a problem where a form is posting back and the model is being lost. As soon as the page is posted back .net is calling the default constructor of the object even though the object already exists.
I have 2 actions, one for GET and one for POST
[HttpGet]
public ActionResult Quote(string sku, string network, string grade )
{
QuoteModel qm = new QuoteModel();
// build model here
return View("Quote", qm);
}
[HttpPost]
public ActionResult Quote(QuoteModel qm, string grade, string network)
{
// update model
return View("Quote",qm);
}
The GET function works perfectly but as soon as the form is posted, the default constructor is called and I lose all the model data.
My view is like:
#model PriceCompare.Models.QuoteModel
<div class="clarify">
#if (Model.clarify == true)
{
using (Html.BeginForm("Quote", "Home", FormMethod.Post))
{
#Html.DropDownList("network", Model.availableNetworks);
#Html.DropDownList("grade", Model.grades);
<button type="submit">Get Quote</button>
}
}
</div>
Why is the default contructor being called when there is an existing model to pass back?
I have tried specifying the model in the form like:
using (Html.BeginForm("Quote", "Home", new { #qm = Model}, FormMethod.Post)
If I do this then the default constructor is not being called but qm is null.
I've been going round in circles here trying to figure this out. Can anyone explain what I am doing wrong?
You can solve this problem by overloading the constructor, and only explicitly calling the second constructor with a boolean parameter set to true.
Model
public class MyModel
{
public int NumberRequested { get; set; }
// This constructor will be called by MVC
public MyModel()
{
RefreshReport();
}
// Call this constructor explicitly from the controller
public MyModel(bool load)
{
if (!load)
{
return;
}
NumberRequested = 10;
RefreshReport();
}
public void RefreshReport()
{
// Do something
}
}
Constructor
public class MyController
{
public ActionResult MyView()
{
var myModel = new MyModel(true);
return View(myModel);
}
[HttpPost]
public ActionResult MyView(MyModel myModel)
{
myModel.RefreshReport();
return View(myModel);
}
}

model returned to view has no effect on field

My Model;
namespace GeneralUtility.Models
{
public class MyModel
{
public int BirthDateYear { get; set; }
public String Details { get; set; }
}
}
My Controller
namespace GeneralUtility.Controllers
{
public class WorkspaceController : Controller
{
public ActionResult MyHelper(MyModel model)
{
if(model.someCondition)
model.Details= "TEST";
else
model.Details= "Some other TEST";
return View(model);
}
}
}
My View
<div data-role="fieldcontain">
#using (Html.BeginForm("MyHelper", "WorkSpace", FormMethod.Post, new { id = "frmMyForm" }))
{
...
<div data-role="fieldcontain">
#Html.EditorFor(x => x.Details )
</div>
...
}
</div>
After I submit my form, I can see the model and any changes I make in MyHelper action method. However, when I make changes and return the model from the controller (I can see the changes in the model while in debug). I get the same value as before in #Html.EditorFor(x => x.Details ) field. What can I do to get the changed Details value of the model to show?
That's because by default ASP.NET MVC returns the model that was passed into a method (using what is stored in the ModelState, if it exists). If it doesn't exist, it uses what you pass to the View.
In order to prevent this, you need to call ModelState.Clear() before returning your view.
Check this blog post for a more detailed explanation.

Categories

Resources