MVC 3 Changing Model in Views with RenderPage - asp.net-mvc-3

I'm having problems when trying to change the model of my view in MVC 3.
First view (index.cshtml) :
#model IEnumerable<MyProgram.MyFrogCollection>
<h1>Welcome to my frog collection</h1>
#foreach(MyProgram.Frog frog in Model)
{
<div class="frogDetails">
#RenderPage("ShowFrogDetails.cshtml", frog);
</div>
}
Second view (ShowFrogDetails.cshtml), that I would like to use all over the site :
#model MyProgram.Frog
<h3>Name:</h3><div class="detail">#Model.Name</div>
<h3>Colour:</h3><div class="detail">#Model.Colour</div>
However when I try to run the page index.cshtml after passing in a list of frog objects I get the following error when getting to the #RenderPage line :
Server Error in '/' Application. The model item passed into the
dictionary is of type
'System.Collections.Generic.List`1[MyProgram.Frog]', but this
dictionary requires a model item of type 'MyProgram.Frog'.
If I were to remove the code from ShowFrogDetails.cshtml and place it in-line within the foreach loop of index.cshtml the results are what I would expect. However this doesn't reuse existing code.
Is there anyway I can change the model to a single Frog object for use in the RenderPage ?
Cheers!

Try like this:
<div class="frogDetails">
#Html.Partial("ShowFrogDetails", frog)
</div>

Related

How can I put a partial view of one type into a regular view of another type?

I’m trying to put a partial view in a regular view that is not of the same type. I create the partial view from my Assignment model and put it in the /Views/Shared folder. Then I tried to call the partial view in a regular view that was based on another model (InstructorIndexData ) and got the error message:
The model item passed into the dictionary is of type 'SchoolIn.ViewModels.InstructorIndexData', but this dictionary requires a model item of type 'SchoolIn.Models.Assignment'.
Here’s a bit of code from the partial view:
#model ...Models.Assignment
<div class="display-label">Grade</div>
<div class="display-field">
#Html.DisplayFor(model => model.Grade)
</div>
And here’s a bit of code from the regular view:
#model SchoolIn.ViewModels.InstructorIndexData
<td> #Html.Partial("_UpdateAttendance")</td>
How can I put a partial view of one type into a regular view of another type?
Thanks for any help.
If you are rendering the view using the Html.Partial method you could pass the model as second argument:
#Html.Partial("_PartialName", item.Grade)
If you are using display/editor templates, this is done automatically:
#Html.DisplayFor(x => x.Grade)
Now assuming that the Grade property is of type Assignment, then the ~/Views/Shared/DislpayTemplates/Assignment.cshtml will be rendered.
If on the other hand you have a collection property:
public IEnumerable<Assignment> Grades { get; set; }
then you could use:
#model SchoolIn.ViewModels.InstructorIndexData
<table>
<tr>
#Html.DisplayFor(x => x.Grades)
</tr>
</table>
and now the Assignment.cshtml display template will automatically be rendered for each element of the Grades collection so that you don't have to write any ugly loops in your view.

My controller viewmodel isn't been populated with my dynamic views model

Im creating an application that allows me to record recipes. Im trying to create a view that allows me to add the basics of a recipe e.g. recipe name,date of recipe, temp cooked at & ingredients used.
I am creating a view that contains some jquery to load a partial view clientside.
On post im having a few troubles trying to get the values from the partial view that has been loaded using jquery.
A cut down version of my main view looks like (I initially want 1 partial view loaded)
<div id="ingredients">
#{ Html.RenderPartial("_AddIngredient", new IngredientViewModel()); }
</div>
<script type="text/javascript">
$(document).ready(function () {
var dest = $("#ingredients");
$("#add-ingredient").click(function () {
loadPartial();
});
function loadPartial() {
$.get("/Recipe/AddIngredient", {}, function (data) { $('#ingredients').append(data); }, "html");
};
});
</script>
My partial view looks like
<div class="ingredient-name">
#Html.LabelFor(x => Model.IngredientModel.IngredientName)
#Html.TextBoxFor(x => Model.IngredientModel.IngredientName)
</div>
<div class="ingredient-measurementamount">
#Html.LabelFor(x => Model.MeasurementAmount)
#Html.TextBoxFor(x => Model.MeasurementAmount)
</div>
<div class="ingredient-measurementtype">
#Html.LabelFor(x => Model.MeasurementType)
#Html.TextBoxFor(x => Model.MeasurementType)
</div>
Controller Post
[HttpPost]
public ActionResult Create(RecipeViewModel vm,IEnumerable<string>IngredientName, IEnumerable<string> MeasurementAmount, IEnumerable<string> MeasurementType)
{
Finally my viewmodel looks like
public class IngredientViewModel
{
public RecipeModel RecipeModel { get; set; }
public IEnumerable<IngredientModel> Ingredients { get; set; }
}
My controller is pretty ugly......im using Inumerble to get the values for MeasurementAmount & MeasurementType (IngredientName always returns null), Ideally I thought on the httppost Ingredients would be populated with all of the on I would be able Ingredients populated
What do I need to do to get the values from my partial view into my controller?
Why don't you take a look at the MVC Controlstoolkit
I think they would do what you want.
Without getting in too much detail. Can you change the public ActionResult Create to use FormCollection instead of a view model? This will allow you to see what data is coming through if any. It would help if you could post it then.
Your view model gets populated by using Binding - if you haven't read about it, it might be a good idea to do that. Finally I would consider wrapping your lists or enums into a single view model.
Possible Problem
The problem could lay with the fact that the new Partial you just rendered isn't correctly binded with your ViewModel that you post later on.
If you inspect the elements with firebug then the elements in the Partial should be named/Id'ed something like this: Ingredients[x].Property1,Ingredients[x].Property2 etc.
In your situation when you add a partial they are probably just called Property1,Property2.
Possible Solution
Give your properties in your partial the correct name that corresponds with your List of Ingredients. Something like this:
#Html.TextBox("Ingredients[x].Property1","")
Of, after rendering your partial just change all the names en ID's with jquery to the correct value.
It happens because fields' names from partial view do not fit in default ModelBinder convention. You should analyze what names fields have in your partial view.
Also you should implement correct way of binding collections to MVC controller. You could find example in Phil's Haack post
Assuming RecipeViewModel is the model being supplied to the partial view, try just accepting that back in your POST controller like this:
[HttpPost]
public ActionResult Create(RecipeViewModel vm)
{
//
}
You should get the model populated with all the values supplied in the form.

Populate a partialview

I feel stupid asking this but I cant seem to get a partial view rendering in a page.
I have created a partial view that im trying to load into my index page. I have called my pv _BusinessDetails basically its a view that returns some customer data.
My pv looks like
#model MyMVC.Models.BusinessModel
<div class="grid">
<div class="grid-header">
<div class="gh-l"></div>
<div class="gh-m">Business Details</div>
<div class="gh-r"></div>
</div>
<div class="grid-row">
<label class="labelBold">Busines Name</label>
<label>#Model.BusinesName</label>
</div>
</div>
From my index page I am trying to call the pv using
#Html.Partial("_BusinessDetails")
which fails so if I add
#Html.Partial("_BusinessDetails",new MyMVC.Models.BusinessModel())
The partial view is loaded however with no data as the controller isn't been hit. In my controller I have tried
public ActionResult _BusinessDetails()
{
return PartialView("_BusinessDetails");
}
public PartialViewResult _BusinessDetails()
{
return PartialView("_BusinessDetails");
}
However neither of them are hit. What have I done wrong?
When rendering a partial view and passing a view model, that view model should already be populated. No controllers/action methods are invoked when using #Html.Partial().
Since you are using this strongly-typed partial view on your home page, consider building its view model in your HomeController's Index() method. Is your index page strongly-typed as well? If so, you can add your partial view's view model as a property of your index page's view model, and pass that when calling #Html.Partial().
On your index page, it would look something like:
#model MyMVC.Models.IndexViewModel
<!-- some HTML here -->
#Html.RenderPartial("_BusinessDetails", Model.BusinessModel)
If your index page is not strongly-typed, you can use the ViewBag object or you can strongly-type it to MyMVC.Models.BusinessModel and use #Html.RenderPartial("_BusinessDetails", Model) (which, while simple, could cause confusion).
Rachel Appel has a nice blog post, as does Mike Brind, if you would like more information.
It's tricky. I've had success with using a model on the main view as a container object:
class MainPageModel {
public BusinessDetailModel BusinessDetails { get; set; }
// ...
}
and then just passing the whole model like #Html.Partial("_BusinessDetails", Model) to my partial views.
When you wrote this,
#Html.Partial("_BusinessDetails",new MyMVC.Models.BusinessModel())
The data is not loaded as your model is empty, so before passing model BusinessModel,fill it before.

MVC 3 Rendering 2-Level Menu as Partial View

I would like to implement a 2-level parent/child menu in my MVC 3 site such as
Company
- Background
- Contact
I have implemented a single, parent level menu as a PartialView like so ...
<div id="menu" class="block">
<ul id="menuItems">
foreach (var item in Model)
{
<li id="#item.Id">#Html.ActionLink(item.Name, item.Action,item.Controller)</li>
}
</ul>
</div>
and then included it on my MasterPage ...
#{Html.RenderAction("MainMenu", "Menu");}
The problem is that I would like to render a second child-menu based on the menu item selected at the parent level. This involves passing the Id of the parent into the controller action that returns the menu model. I'm not sure how I can pass this parent Id into the controller action. Can anyone provide any insights into this? I'm using MVC3 & Razor.
You may want to check out MvcSiteMapProvider which handles multilevel menu and sitemaps.
Looks like you're using Razor and while I'm not super familiar with that I'll take a shot at it. Basically you're going to pass a new object that has a single property of "id" to the MainMenu view. That will create another menu. Your MainMenu action should take an optional parameter of id.
public ActionResult MainMenu(int? id = null) {
...
}
Here is what your new list item would look like.
<li id="#item.Id">#Html.ActionLink(item.Name, item.Action,item.Controller)
#{Html.RenderAction("MainMenu", "Menu", new { id = item.Id });}
</li>

MVC 3 with Razor question about partial views

MVC 3 with Razor question about partial views.
I have this :
#model MvcGroupie.Models.Message
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>Message</legend>
<div class="display-label">postCreator</div>
<div class="display-field">#Model.postCreator</div>
<div class="display-label">postDate</div>
<div class="display-field">#String.Format("{0:g}", Model.postDate)</div>
<div class="display-label">postSubject</div>
<div class="display-field">#Model.postSubject</div>
<div class="display-label">postBody</div>
<div class="display-field">#Model.postBody</div>
</fieldset>
#Html.Partial("~/Views/Shared/replyPartial.cshtml")
<p>
#if(Model.postCreator == User.Identity.Name) {#Html.ActionLink("Edit", "Edit", new { id=Model.postID } + " | ")}
#Html.ActionLink("Reply", "Reply", new { id=Model.postID }) |
#Html.ActionLink("Back to List", "Index")
</p>
For a very simple post and reply MVC app im playing with for learning. I cant get a partial to display for replies :/
If i add the partial i get 'MvcGroupie.Models.Message', but this dictionary requires a model item of type 'MvcGroupie.Models.Reply'. Ok, so you cant ever use diff models on the same page? The first line starts with #model MvcGroupie.Models.Message so i can access the model.postSubject and the like. But if i want to add the replies and have people able to reply from the same page it doesnt allow it, they would fall under #model MvcGroupie.Models.Reply...
Curious how to get around this... I tried #Html.Partial("~/Views/Shared/replyPartial.cshtml", Model.Reply) but it doesnt recognize Model.Reply ....
Serious roadblock in my way of learning any help?
When you make the call to render a partial view that takes a different model you need to pass the model to that view. The default behavior is that the partial view will use the same model as the view that called it, but that won't work in your case because the models are different.
Try this:
#Html.RenderPartial("~/Views/Shared/replyPartial.cshtml", Model.Replies)
I'm assuming your Message object has a Replies property. Don't forget to do a null check in your partial view in case the message doesn't have any replies.

Resources