Wiring partial view to model - asp.net-mvc

I'm in a bit of a rut with MVC3 partial views. What I'm trying to do is have a partial view within one of my pages, and have that data from the partial view stored in the model that gets passed back into the main view. Though, what's happening right now is that after submitting the data, the model returned back to the controller has the partial view model set as null.
Model
public class MyModel {
...(other variables)...
[Required]
[NotMapped]
public virtual MyPartialView myPartial { get; set; }
}
View
#model MvcPartialViewExample.Models.MyModel
#{
ViewBag.Title = "Create";
}
#using (Html.BeginForm()) {
#Html.ValidationSummary(true)
<fieldset>
...(other data)...
#{
Html.RenderPartial("_MyPartialView", Model.MyPartialView, new ViewDataDictionary());
}
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Controller
public class MyModelController : Controller
{
private MyModelContext db = new MyModelContext();
//
// GET: /PartialViewTesting/Create
public ActionResult Create()
{
return View(new MyModel());
}

If you want to pass the Model.MyPartialView object back to the controller, then you need to add another Action method to the controller. Should look something like this:
[HttpPost]
public ActionResult Create(MyPartialView model)
{
// handle postback here
}

Related

How to avoid view code duplication in MVC?

I've made a very simple mockup of my problem.
If i have a complex person viewModel:
public class PersonViewModel
{
public string Name { get; set; }
public List<DogViewModel> Dogs { get; set; }
}
public class DogViewModel
{
public string Name { get; set; }
}
And i have 2 views : to edit person and create a person :
#model Custom.Models.PersonEditViewModel
#{
ViewBag.Title = "Edit";
}
<h2>Edit Person</h2>
<div class="PersonDataArea">
//this contain identical html in Create and Edit view
</div>
<div class="SelectDogAre">
//this contain identical html in Create and Edit view
</div>
<input type="button" value="save" />
#model Custom.Models.PersonCreateViewModel
#{
ViewBag.Title = "Create";
}
<h2>Create Person</h2>
<div class="PersonDataArea">
//this contain identical html in Create and Edit view
</div>
<div class="SelectDogAre">
//this contain identical html in Create and Edit view
</div>
<input type="button" value="save"/>
And of course 2 ViewModels for each view :
public class PersonEditViewModel
{
public PersonViewModel Person { get; set; }
}
public class PersonCreateViewModel
{
public PersonViewModel Person { get; set; }
}
Question :
as you can see i have 2 identical areas in Create and Edit views, and i want to avoid to suplicate code. I cant use Partial views because model in partial view will not be bound on post. How to avoid duplication of the view code??
You definitely need to use a Partial View.
First of all, you don't need two separate View Models. Just the PersonViewModel is enough.
Then you'll create a partial view _PersonEdit.cshtml (by the way you are missing the form in your code):
#model Custom.Models.PersonViewModel
#using(Html.BeginForm())
{
<div class="PersonDataArea">
//this contain identical html in Create and Edit view
</div>
<div class="SelectDogAre">
//this contain identical html in Create and Edit view
</div>
<input type="button" value="save"/>
}
And, two Views for Create and Edit:
Create:
#{
ViewBag.Title = "Create";
}
<h2>Create Person</h2>
#Html.Partial("_PersonEdit", Model)
Edit:
#{
ViewBag.Title = "Edit";
}
<h2>Edit Person</h2>
#Html.Partial("_PersonEdit", Model)
Alternatively, you can create only one view for both actions, and pass the ViewBag.Title from the controller to the view.

how to pass data from view to controller

I am new to asp.net MVC5 and i am trying to pass data from view to controller as a string.
Here is controller class:
namespace Movies.Controllers
{
public class HelloWorldController : Controller
{
// GET: HelloWorld
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult welcome(FormCollection fc, string reportName)
{
ViewBag.Message = reportName;
return View();
}
}
}
Here is Index View:
#{
ViewBag.Title = "MVC Movies";
}
<h2>My Movies List</h2>
<p>Hellow from our view template</p>
#using (Html.BeginForm("Welcome", "HelloWorld", FormMethod.Get))
{
<p>
<input type="text" name="reportName" />
<input type="submit" />
</p>
}
Here is welcome view:
#{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>welcome</h2>
#{
ViewBag.Title = "Welcome";
}
<ul>
#for (int i = 0; i < 2; i++)
{
<li>#ViewBag.Message</li>
}
</ul>
Actually my Index method is passing a view that will have a textbox for string in it in a form and then on clicking submit button application should pass that string in the Welcome method in the same controller. On clicking submit button browser is showing a windows that resources con't be found.
Whats the problem..? thank you for your time..:)
1) The action name is case sensitive, you are using "Welcome" in the form definition , but the action must has the name "welcome" with w lower case.
2) Your form is doing a GET but you are specting a POST in the action
[HttpGet]
public ActionResult welcome(FormCollection fc, string reportName)
{
ViewBag.Message = reportName;
return View();
}
Replace FormMethod.Get with FormMethod.Post in your beginform.
Modify FormMethod.Get to FormMethod.Post:
#using (Html.BeginForm("Welcome", "HelloWorld", FormMethod.Post))
{
<p>
<input type="text" name="reportName" />
<input type="submit" />
</p>
}
Change your action implementation to this:
[HttpPost]
public ActionResult welcome(FormCollection fc)
{
ViewBag.Message = fc["reportName"];
return View();
}
However, I'd strongly suggest that you create a view model for your form and use it instead of FormCollection.

Model change in post action not visible in Html.TextBoxFor?

This must be something very obvious but for me it looks very strange. I have simple controller, model with one property, and view which displays value of property and renders editor for that property. When I click the button, form is posted and exclamation mark is appened to property. This exclamation mark is visible in my view but only in p tag, not in input tag rendered by Html.TextBoxFor().
Why Html.TextBoxFor() ignores that I updated my model in post action?
Is there any way to change this behavior of Html.TextBoxFor()?
View
#model ModelChangeInPostActionNotVisible.Models.IndexModel
#using (Html.BeginForm())
{
<p>#Model.MyProperty</p>
#Html.TextBoxFor(m => m.MyProperty)
<input type="submit" />
}
Model
namespace ModelChangeInPostActionNotVisible.Models
{
public class IndexModel
{
public string MyProperty { get; set; }
}
}
Controller
namespace ModelChangeInPostActionNotVisible.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new IndexModel { MyProperty = "hi" });
}
[HttpPost]
public ActionResult Index(IndexModel model)
{
model.MyProperty += "!";
return View(model);
}
}
}
HTML after clicking on submit button
<form action="/" method="post"> <p>hi!</p>
<input id="MyProperty" name="MyProperty" type="text" value="hi" /> <input type="submit" />
</form>
This is by design.
The helper methods are using the ModelState, thus if the response of your request is using the same Model, it will display the value that was posted.
This is to allow you to render the same view in the situation where the validation would have failed.
To make sure you display the new information add : ModelState.Clear(); before you return.
Read more here : http://blogs.msdn.com/b/simonince/archive/2010/05/05/asp-net-mvc-s-html-helpers-render-the-wrong-value.aspx
namespace ModelChangeInPostActionNotVisible.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
return View(new IndexModel { MyProperty = "hi" });
}
[HttpPost]
public ActionResult Index(IndexModel model)
{
model.MyProperty += "!";
ModelState.Clear();
return View(model);
}
}
}
Yan Brunet is absolutely correct that the variable needs to be removed from the ModelState in order to be modified in the controller. You don't have to clear the entire ModelState, though. You could do the following to remove just the variable to want to modify:
ModelState.Remove("MyProperty");
This would be useful in case you wanted to retain other values which the user had entered.

how to add some own forms in a ASP.NET MVC create view?

i have a problem, i had created a controller and a view for adding a new item from a specific model. the view looks like:
#modelModels.UserItem
#{
ViewBag.Title = "New";
}
<h2>New</h2>
<script src="#Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="#Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
<fieldset>
<legend>Device</legend>
<div class="editor-label">
#Html.LabelFor(model => model.name)
</div>
<div class="editor-field">
#Html.EditorFor(model => model.name)
#Html.ValidationMessageFor(model => model.name)
</div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
and the controller:
[HttpPost]
public ActionResult New(UserItem useritem)
{
if (ModelState.IsValid)
{
db.UserItems.AddObject(useritem);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(useritems);
}
how i want to add a dropdown to the form in the view like this:
<select id="Select1">
<option>MARS</option>
</select>
how to access the data from the form after it was submitted in the controller?
Have view model for your page,this view model will be used in your view. So, only include fields from your model that you really need. In Get action you should create this view model and get the needed properties from your model and map them to your view model.
public class UserItemViewModel
{
/* Properties you want from your model */
public string Property1 { get; set; }
public string Property2 { get; set; }
public string Property3 { get; set; }
/* Property to keep selected item */
public string SelectedItem { get; set; }
/* Set of items to fill dropdown */
public IEnumerable<SelectListItem> SelectOptions { get; set; }
/* Fill the SelectListHere. This will be called from index controller */
public void FillOptions()
{
var items = new[] { "Mars", "Venus" }.
Select(x => new SelectListItem { Value = x, Text = x });
SelectOptions= new SelectList(items, "Value", "Text");
}
}
Change controller for receiving ViewModel instead of Model itself.
[HttpPost]
public ActionResult New(UserItemViewModel useritem)
{
/* Repopulate the dropdown, since the values are not posted with model. */
userItem.FillOptions();
if (ModelState.IsValid)
{
/* Create your actual model and add it to db */
// TODO: Map your properties from model to view model.
// Let's say you created a model with name userItemModel
db.UserItems.AddObject(userItemModel);
db.SaveChanges();
return RedirectToAction("Index");
}
return View(useritem);
}
You might need to change Index view controller little.(to fill dropdown)
[HttpGet]
public ActionResult Index()
{
/* Create new viewmodel fill the dropdown and pass it to view */
var viewModel = new UserItemViewModel();
viewModel.FillOptitons();
//TODO : From your model fill the required properties in view model as I mention.
return View(viewModel);
}
And your view,
/* Strongly typed view with viewmodel instead of model itself */
#modelModels.UserItemViewModel
/* This is the dropdown */
#Html.DropDownListFor(m => m.SelectedItem, Model.SelectOptions)
Add that property to your model
Use builtin EditorFor(preffered) or hand-written html to generate client-side input for that property.
Access submitted value by inspecting that property when user submits the form
I like emre's proposition of having a viewModel and I think is the Best solution to your question however just in case you don't want to go that way (you must have a really good reason because it is best) and still want a way to access the values of a form directly you can always use:
var x = Request["myFiledName"];
inside your controller to get to the values passed by your form.

Model value lost on postback

I have the following models:
class A
{
// ...some properties
public B InnerField { get; set; }
}
and
class B
{
public int Id { get; set; }
// ..other properties
}
and a page that has a model Class A and inside the page I have a partial view bound to Class B inside a form.
The value of the Id (in the partial view) is set correctly to the model's Id value (different from 0) but when I submit the page the model has the Id value 0. The Id value is not modified in the component or elsewhere.
Page
...other parts of main page
<%using (Html.BeginForm("ModifyHotel", "Hotel",
FormMethod.Post, new { enctype = "multipart/form-data"}))
{%>
<% Html.RenderPartial("~/Views/Shared/ModifyBaseItem.ascx",
new ModifyItemRequestBaseView() { ItemId = Model.Item.Id });%>
<%}%>
...other parts of main page
Partial View
...other parts of partial view
<br/>
Add Photo: <%:Html.FileBoxFor(x => x.PhotoFile, null)%>
<br/>
Add Video: <%:Html.FileBoxFor(x => x.VideoFile, null)%>
<br/>
<input type="submit" value="Submit changes" />
...other parts of partial view
What can I do to keep the value of the inner model when the post is made?
Thanks,
Controller:
public class HomeController : Controller
{
public ActionResult Index()
{
A model = new A() { InnerField = new B() { Id = 5 }};
return View(model);
}
[HttpPost]
public ActionResult Index(B model)
{
//on postback the model should have the value 5 here
return View();
}
}
View:
#model MvcApplication11.Models.A
#using (Html.BeginForm())
{
#Html.Partial("_IndexForm", Model.InnerField)
<input type="submit" />
}
Partial:
#model MvcApplication11.Models.B
#Html.EditorFor(m => m.Id)

Resources