Rendering Partial Views in a Loop in MVC3 - asp.net-mvc-3

I have a pretty simple scenario, Model for my view is a List.
Loop through List like
#foreach(CustomObject obj in Model)
{
Html.Partial("_TrackingCustomObject",obj)
}
So i was expecting to have number of partial views according to my list.
Partial View has been developed accordingly.
There is no error on page. It just does not show any data that is supposed to display by partial views.
What is the reason of not showing any data?

You are missing an #:
#foreach(CustomObject obj in Model)
{
#Html.Partial("_TrackingCustomObject", obj)
}
But why writing foreach loops when you can use editor/display templates? Like this:
#model IEnumerable<CustomObject>
#Html.EditorForModel()
and then simply define the corresponding editor template (~/Views/Shared/EditorTemplates/CustomObject.cshtml) that will automatically be rendered for each element of your model:
#model CustomObject
<div>
#Html.EditorFor(x => x.Foo)
</div>
Simple and conventional :-)

You're missing the Razor symbol #:
#foreach(CustomObject obj in Model)
{
#Html.Partial("_TrackingCustomObject",obj)
}
Also make sure your partial view is using the object type CustomObject as the Model.
#model MyProject.Models.CustomObject
<h1>Yeah we're in a partial! #Model.SomeProperty </h1>
To try and drill down to where the error is, try placing some static text inside the PartialView.
<p>Some text</p>
If your collection has 10 items, then you should see 10 of these paragraphs. Next once this works, focus on displaying some property in each item.
#model MyProject.Models.CustomObject
<p>Some text</p>
<p>#Model.SomeProperty</p>

When you are creating html form using #Html.BeginForm() you have to wrap the remaining stuf inside a <div> or other container else the html elements won't get rendered.
Ex.
this won't work
#using(Html.BeginForm())
{
Html.EditorFor(m => m.Name)
}
this will work
#using(Html.BeginForm())
{
<div>
#Html.EditorFor(m => m.Name)
</div>
}

Bit late in the day, but this worked for me in MVC 4:
#foreach (var p in #Model.RelatedCards)
{
Html.RenderPartial("_ThumbPartial", p);
}

Try this:
#Html.RenderPartial("_TrackingCustomObject",obj)

This is too old but someone can use it.
#foreach(CustomObject obj in Model)
{
<text>
Html.Partial("_TrackingCustomObject",obj)
</text>
}

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.

passing data from view to controller on asp.net mvc 3

i have problem to pass data from view to controller , i have view that is strongly typed with my viewmodel "TimeLineModel", in the first i passed to this view my viewmodel from action on my controller
public ActionResult confirmation(long socialbuzzCompaignId)
{
return View(new TimeLineModel() { socialBuzzCompaignId = socialbuzzCompaignId, BuzzMessages = model });
}
with this i can get info from my action and display it on view , but i have other action POST which i won't get my view model to do some traitement
[HttpPost]
public ActionResult confirmation(TimeLineModel model)
{
}
i can get some propretie of the model but in others no , for example i can get the properti "socialBuzzCompaignId" of model , but other propertie like "IEnumerable BuzzMessages" i can't get it , i dont now why !!
this is the content of my view
#model Maya.Web.Models.TimeLineModel
#{
ViewBag.Title = "confirmation";
}
#using (Html.BeginForm())
{
<h2>confirmation</h2>
<fieldset>
#foreach (var msg in Model.BuzzMessages)
{
<div class="editor-label">
#msg.LongMessage
</div>
<br />
}
<p>
<input type="submit" value="Save" />
</p>
</fieldset>
}
You need to include BuzzMessages properties within a form element. Since it's not editable, you'd probably want to use hiddens. There are two ways to do this. Easiest is instead of doing a foreach loop, do a for loop and insert them by index.
#for (int i =0; i<Model.BuzzMessages.Count(); i++v)
{
<div class="editor-label">
#Model.BuzzMessages[i].LongMessage
#Html.HiddenFor(m => m.BuzzMessages[i].LongMessage);
</div>
<br />
}
but to do this you'd need to use an IList instead of an IEnumerable in your view model to access by index.
Alternatively, you could create an Editor Template named after your BuzzMessages class (whatever its name is).
#model BuzzMessagesClass
#Html.HiddenFor(m => m.LongMessages)
<!-- Include other properties here if any -->
and then in your main page
#Html.EditorFor(m => m.BuzzMessages)
Check out http://coding-in.net/asp-net-mvc-3-how-to-use-editortemplates/ or search stack overflow if the details of editor templates confuse you.
Just like any HTML POST method, you have to get the data back to the Controller somehow. Just simply "showing" the data on the page doesn't rebind it.
You have to put the data in an input (or a control that will post back) to the appropriate model property name.
So, if you have a model property with name FirstName and you want this data to be rebound to the model on POST, you have to supply it back to the model by placing an "input hidden" (or similar control that postbacks) with the ID of FirstName will rebind that property to the model on POST.
Hope that explains it.
#foreach (var msg in Model.BuzzMessages)
{
<div class="editor-label">
#msg.LongMessage
<input type="hidden" name="BuzzMessages.LongMessage" value="#msg.LongMessage" />
</div>
}
It will post array of LongMessages. Get values like this:
[HttpPost]
public ActionResult confirmation(TimeLineModel model, FormCollection collection)
{
var longMessages = collection["BuzzMessages.LongMessage"];
}

Nested edit templates in mvc razor

I have seen many versions of this question but the answers always turn into "you don't need to do that" and never an answer.
I have a list of attributes about a product that I want to show in an unordered list with checkboxes to select particular attributes.
In My Model:
public List<ProductAttribute> ProductAttributes {get;set;}
in my Create.cshtml:
<div Class="ProductAttributes">
#Html.EditorFor(m => m.ProductAttributes, "ProductAttributeSelectorList")
</div>
In my ProductAttributeSelectorList.cshtml:
#model List<Models.DisplayLocationAttribute>
<div class="AttributeSelector">
<ul>
#foreach (var item in Model)
{
<li>
#Html.EditorFor(_ => item, "EditLocationAttributeList")
</li>
}
</ul>
</div>
And finally, in my EditLocationAttributeList.cshtml
#model Models.DisplayLocationAttribute
#Html.HiddenFor(m => m.Id)
#Html.CheckBoxFor(m => m.IsSelected)
<a href="#" alt="#Model.Description" >#Model.Name</a>
This all displays on the page perfectly I can style it like I want with CSS, but when the submit returns, my model.ProductAttributes collection is null.
I know I can bind directly to the EditLocationAttributeList and it will display and return a populated model.ProductAttributes if I use this:
#Html.EditorFor(m => m.ProductAttributes, "EditLocationAttributeList")
but now I do not have the unordered list that I would like to have. I could treat the template like an Item Template and have the line item tags embeded in that template but that seems smelly to have a template that is tightly coupled to another template.
Any Ideas?
Thanks in advance,
Tal
model.ProductAttributes is null, because the DefaultModelBinder is not able to reference each DisplayLocationAttribute back to the ProductAttribute property of your model. The simplest solution is to name your list elements as an array, so that for example each IsSelected element is named in the style ProductAttributes[n].IsSelected.
Add the following to ProductAttributeSelectorList.cshtml:
#model List<Models.DisplayLocationAttribute>
#{
var i = 0;
}
<div class="AttributeSelector">
<ul>
#foreach (var item in Model)
{
this.ViewData.TemplateInfo.HtmlFieldPrefix = "ProductAttributes[" +
i.ToString() + "]";
i++;
<li>
#Html.EditorFor(_ => item, "EditLocationAttributeList")
</li>
}
</ul>
</div>
#{
this.ViewData.TemplateInfo.HtmlFieldPrefix = "";
}
This will give you an indexed array, which the DefaultModelBinder will be able to associate to ProductAttributes. However, it builds a hard dependency to the name ProductAttributes. You can get around the hard dependency by several methods, such as passing the property name in the ViewBag.

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.

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