I am developing a web app using ASP.NET MVC 5. I have multiple partial views and their corresponding models, but only one controller corresponding to the main view, that uses below code to display each of the partial views.
@{Html.RenderPartial("PartialViewName");}
My question is, how do I pass the form data from all the partial views (including the main view) to the main controller?
Initially, when I added only 1 partial view, I added it's model as a parameter to the main controller's public ActionResult Index(MainModelName model1, PartialModelName pmodel1)
. and that worked fine and I could access the data from the partial view in the main controller.
But, when I added the 2nd partial view and updated the public ActionResult Index(...)
with an additional partial model parameter, it didn't help, as in the data is not being passed from the partial view to the main controller. though I don't get any error.
My main model class has the object references of the partial models as its data members. From what I read, I need to have a list of models as a parameter to the method in the main controller, but my models are not sub-types.
What's the idiomatic way of handling such a situation?
Thank you!
EDIT1 : Here's the code for a sample app, I get null reference error while accessing mainModel.PartialModel2.Pm2
in MainController.cs, while I can access mainModel.PartialModel1.Pm1
properly.
MainModel.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class MainModel
{
private int mm1;
private PartialModel1 partialModel1;
private PartialModel2 partialModel2;
public int Mm1 { get => mm1; set => mm1 = value; }
public PartialModel1 PartialModel1 { get => partialModel1; set => partialModel1 = value; }
public PartialModel2 PartialModel2 { get => partialModel2; set => partialModel2 = value; }
}
}
PartialModel1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class PartialModel1
{
private int pm1;
public PartialModel1()
{
}
public int Pm1 { get => pm1; set => pm1 = value; }
}
}
PartialModel2.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class PartialModel2
{
private int pm2;
public PartialModel2()
{
}
public int Pm2 { get => pm2; set => pm2 = value; }
}
}
Index.cshtml
@model TestApp.Models.MainModel
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MainModel</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Mm1, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Mm1, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Mm1, "", new { @class = "text-danger" })
</div>
</div>
<div class="form-group">
@{ Html.RenderPartial("Partial1", Model); }
@{ Html.RenderPartial("Partial2", Model); }
</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>*@
</body>
</html>
Partial1.cshtml
@model TestApp.Models.MainModel
@using (Html.BeginForm("MainModel"))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PartialModel1</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.PartialModel1.Pm1, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.PartialModel1.Pm1, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.PartialModel1.Pm1, "", new { @class = "text-danger" })
</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>*@
Partial2.cshtml
@model TestApp.Models.MainModel
@using (Html.BeginForm("MainModel"))
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PartialModel2</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.PartialModel2.Pm2, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.PartialModel2.Pm2, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.PartialModel2.Pm2, "", new { @class = "text-danger" })
</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>*@
MainController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestApp.Models;
namespace TestApp.Controllers
{
public class MainController : Controller
{
// GET: Main
[HttpGet]
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(MainModel mainModel)
{
//Access mainModel.PartialModel1.Pm1
//Access mainModel.PartialModel2.Pm2
string msg = mainModel.PartialModel1.Pm1 + " " + mainModel.PartialModel2.Pm2;
ViewBag.message = msg;
return View("Success");
}
}
}
EDIT 2: If I just keep it @{ Html.RenderPartial("Partial2"); }
, I get this error - The model item passed into the dictionary is of type 'TestApp.Models.Main', but this dictionary requires a model item of type 'TestApp.Models.Partial2'.
MainController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using TestApp.Models;
namespace TestApp.Controllers
{
public class MainController : Controller
{
// GET: Main
[HttpGet]
public ActionResult Index()
{
return View(new Main() { Partial1 = new Partial1(), Partial2 = new Partial2() });
}
[HttpPost]
public ActionResult Index(Main mainModel)
{
//Access mainModel.PartialModel1.Pm1
//Access mainModel.PartialModel2.Pm2
string msg = mainModel.Partial1.Pm1 + " " + mainModel.Partial2.Pm2;
ViewBag.message = msg;
return View("Success");
}
}
}
Main.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class Main
{
public int Mm1 { get; set; }
public Partial1 Partial1 { get; set; }
public Partial2 Partial2 { get; set; }
}
}
Partial1.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class Partial1
{
public Partial1()
{
}
public int Pm1 { get; set; }
}
}
Partial2.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApp.Models
{
public class Partial2
{
public Partial2()
{
}
public int Pm2 { get; set; }
}
}
Index.cshtml
@model TestApp.Models.Main
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Index</title>
</head>
<body>
@using (Html.BeginForm())
{
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>MainModel</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Mm1, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Mm1, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Mm1, "", new { @class = "text-danger" })
</div>
</div>
@{ Html.RenderPartial("Partial2"); }
@{ Html.RenderPartial("Partial1"); }
<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>*@
</body>
</html>
Partial1.cshtml
@model TestApp.Models.Partial1
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PartialModel1</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Pm1, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Pm1, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Pm1, "", new { @class = "text-danger" })
</div>
</div>
</div>
@*<div>
@Html.ActionLink("Back to List", "Index")
</div>*@
Partial2.cshtml
@model TestApp.Models.Partial2
@Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>PartialModel2</h4>
<hr />
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
<div class="form-group">
@Html.LabelFor(model => model.Pm2, htmlAttributes: new { @class = "control-label col-md-2" })
<div class="col-md-10">
@Html.EditorFor(model => model.Pm2, new { htmlAttributes = new { @class = "form-control" } })
@Html.ValidationMessageFor(model => model.Pm2, "", new { @class = "text-danger" })
</div>
</div>
</div>
@*<div>
@Html.ActionLink("Back to List", "Index")
</div>*@
@{Html.RenderPartial("PartialViewName", Model);}
- penleychanmain
andpartial
form. etc. Normally you would do what I mentioned above and pass in yourViewModel
then you would be able to access it from yourcontroller
- penleychan