Trouble passing ViewModel to Partial View - asp.net-mvc

My ViewModel class (ItemViewModel.cs) looks like this:
public class ItemViewModel
{
public ItemViewModel(xxx.Product product)
{
this.product = product;
}
private readonly xxx.xxx.Product product;
private readonly Pers pers;
private readonly Item item;
public xxx.xxx.Product Product
{
get{ return product;}
}
public Item Item
{
get { return item; }
}
public ItemList Items
{
get { return product.Items; }
}
public Pers Pers
{
get { return pers; }
set { value = pers; }
}
public PersList PersList
{
get { return product.PersList; }
}
}
The view has this code defined in it (I took out some other case lines, just to show one of them as an example):
<%# Page Language="C#" MasterPageFile="~/Views/Shared/MasterPages/Item.Master" Inherits="System.Web.Mvc.ViewPage<xxx.ViewModels.ItemViewModel>" %>
<% foreach (Pers p in Model.Perslist)
{
switch(p.DispType)
{
case DisType.Dropdown:
Model.Pers = p;
Html.RenderPartial("~/Views/Shared/Controls/Custom/PForm/DropDown.ascx",*Model);
break;
}
}
%>
And the RenderPartial looks like this:
<fieldset>
<div class="xxx">
<span class="xxx">*</span><label><%=Model.Pers.Name %></label>
<p class="xxx"><%=Model.Pers.Info %></p>
</div>
<div class="formField"><% Html.DropDownList(Model.Pers.Name, new SelectList(Model.Items[0].DropdownItems));%></div>
</fieldset>
The problem or dilemma I'm having is I not only need the p from the foreach but the entire ItemViewModel instance that was originally passed to my View. Because I need to use the Pers in that foreach as well as be able to reference the Items. So what I tried is to set the Pers property of the ItemViewModel class instance to the current p in the foreach. Then tried to send the whole Model (now that I have that Pers set on the property) which is of type ItemViewModel so that I can now use the property Pers on that object and also still be able to reference the Items property that was populated already when it hit the View.
So when the page renders I get:
System.NullReferenceException: Object reference not set to an instance of an object.
for this line:
<span class="xxx">*</span><label><%=Model.Pers.Name %></label>
So far I'm unsuccesful because I still get a null reference error on the property Pers when I attempt to use the ITemViewModel in my Partial View.

This could be because your partial view file needs this line above your html:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<xxx.ViewModels.**ItemViewModel**>" %>
So this is how your partial view should look:
<%# Page Language="C#" Inherits="System.Web.Mvc.ViewPage<xxx.ViewModels.**ItemViewModel**>" %>
<fieldset>
<div class="xxx">
<span class="xxx">*</span><label><%=Model.Pers.Name %></label>
<p class="xxx"><%=Model.Pers.Info %></p>
</div>
<div class="formField"><% Html.DropDownList(Model.Pers.Name, new SelectList(Model.Items[0].DropdownItems));%></div>
</fieldset>

Good God, I set the property wrong. resolved. duh.

Related

I use viewmodel to bass to list of objects one to use in partialview of strongly type but this error is occurred

The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[MvcApplication1.Models.News]', but this dictionary requires a model item of type 'MvcApplication1.Models.News'.
//my Controller
public class HomeController : Controller
{
CouncilDb _db=new CouncilDb() ;
public ActionResult Index()
{
var News = _db.News
.Take(10);
var Banner = (from r in _db.Banner orderby r.id descending select r).FirstOrDefault();
maz model = new maz();
model.Banner = Banner;
model.News = News.ToList();
return View(model);
}
protected override void Dispose(bool disposing)
{
if (_db != null)
{
_db.Dispose();
}
base.Dispose(disposing);
}
}
public class maz
{
public List<News> News { get; set; }
public Banner Banner { get; set; }
}
//Index view
#model MvcApplication1.Controllers.maz
#{
ViewBag.Title = "Home Page";
}
<!-- Banner -->
<!-- Banner -->
<div id="banner">
<h2> #Model.Banner.H2</h2>
<span class="byline"> #Model.Banner.Span </span>
</div>
#Html.Partial("_News",Model.News )
//Partialview
#model MvcApplication1.Models.News
<!-- Carousel -->
<div class="carousel">
<div class="reel">
<article>
<a class="image featured">
<img src="#Model.ImgUrl " alt="" /></a>
<header>
<h3>#Html.ActionLink(#Model.Title , "serch", "Home")</h3>
</header>
<p>#Model.Body </p>
</article>
</div>
</div>
The .News property of your model is of type List<News> not News so the model declaration in your partial view and the model you are passing to it don't match.
Depending on what you want to acheive, you can either loop through the List inside the index view:
#foreach (var news in Model.News)
{
#Html.Partial("_News", news)
}
or adjust the partial view model declaration and loop there
#model List<News>
....
#for (var news in Model)
{
<article>
<a class="image featured">
<img src="#news.ImgUrl" alt="" /></a>
<header>
<h3>#Html.ActionLink(#news.Title , "serch", "Home")</h3>
</header>
<p>#news.Body</p>
</article>
}
The error is pretty straightforward, once you get past the generic syntax. In C#-speak it's saying this:
The model item passed into the dictionary is of type 'List<News>',
but this dictionary requires a model item of type 'News'.
Your partial view is declared with a #model clause that specifies an item of type News:
#model MvcApplication1.Models.News
but when you pass in data to that partial view, what you're passing in is a List<News>:
#Html.Partial("_News",Model.News)
What you probably want is a loop (a #foreach or similar) that creates one partial view for each element in your News list.

Error when retrieving records

I'm a beginner in ASP.NET MVC. I'm getting a error while trying to retrieve records from the database.
'System.Collections.Generic.List'
does not contain a definition for 'CategoryName'
LINQ to SQL Class:
Model:
namespace MvcApplication1.Models
{
public class CategoryRepository
{
private BusDataClassesDataContext dc = new BusDataClassesDataContext();
public List<tblCategory> GetAllCategory()
{
return dc.tblCategories.ToList();
}
}
}
Controller:
public class CategoryController : Controller
{
//
// GET: /Category/
CategoryRepository cat = new CategoryRepository();
public ActionResult ViewCategory()
{
var category = cat.GetAllCategory().ToList();
return View("ViewCategory", category);
}
}
View:
<p>
Category Name:<%=Html.Encode(Model.CategoryName)%>
</p>
<p>
Description:<%= Html.Encode(Model.Description)%>
</p>
UPDATE:
You are passing List<tblCategory> to the view. Hence the Model here will be the generic list. That is the reaons why you are getting the error message:-
'System.Collections.Generic.List' does not contain a definition for 'CategoryName'
Did you intend to pass tblCategory or else did you intend to iterate thought the model to get to each tblCategory?
You can do this way
<% foreach(var category in Model)
{%>
<p>
Category Name:<%=Html.Encode(category.CategoryName)%>
</p>
<p>
Description:<%= Html.Encode(category.Description)%>
</p>
<% } %>
On a little bit different note.
You are already returning the type as GenericList in your method.
public List<tblCategory> GetAllCategory()
{
return dc.tblCategories.ToList();
}
You don't need to again perform an ambiguous .ToList() conversion.
var category = cat.GetAllCategory().ToList();
Use this::
<% foreach (var category in Model)
ruther than ::
#foreach (var category in Model)
in the view.
Like This
<% foreach (var category in Model)
{ %>
<p>
Category Name :<%=Html.Encode(category.CategoryName)%></p>
<p>
Description :<%=Html.Encode(category.Description)%></p>
<% } %>

ASP.NET Mvc Question

I wrote something like this in the controller.
public ActionResult Giris()
{
ViewData["Tarif"] = (from t in _entities.Tarif
join k in _entities.Kullanici on t.KID equals k.KID
select new {KAdi = k.KAdi, TAdi = t.TAdi})
.Take(4);
return View();
}
I am using it as below in the view page.
<% foreach (var item in (IEnumerable<dynamic>)ViewData["Tarif"]) { %>
<div class="begenilen-video" style="float:left">
<img class="video-resmi" alt="reklam" src="../../Uygulama/Resimler/Reklam/1.jpg" />
<span class="benzer-yemek-tarifi-adi"></span><%=item.TAdi %><br />
<span class="benzer-yemek-tarifi-ekleyen">Ekleyen: </span><br />
<span class="benzer-yemek-tarifi-izlenme">İzlenme: </span>
</div>
<% } %>
However,I am receive the error in the select statement.How do I invoke the items in the view page?
Thanks in advance.
As a guess because you haven't posted the error:
The object being stored in ViewData["Tarif"] will be of the type IQueryable<T> where T is an anonymous object and in your view you are casting to IEnumerable<dynamic>. IQueryable is also lazily loaded so you will be trying to execute your query once the object has been disposed.
You should really create a strongly typed view model
public class ViewModelType {
public IEnumerable<TarifType> Tarif { get; set; }
}
Tarif type
public class TarifType {
public string KAdi { get; set; }
public string TAdi { get; set; }
}
controller
public ActionResult Giris() {
var viewModel = new ViewModelType();
viewModel.Tarif = (from t in _entities.Tarif
join k in _entities.Kullanici on t.KID equals k.KID
select new TraifType { KAdi = k.KAdi, TAdi = t.TAdi }
).Take(4)
.ToList();
return View(viewModel);
}
view
<% foreach (var item in viewModel.Tarif) { %>
<div class="begenilen-video" style="float:left">
<img class="video-resmi" alt="reklam" src="../../Uygulama/Resimler/Reklam/1.jpg" />
<span class="benzer-yemek-tarifi-adi"></span><%=item.TAdi %><br />
<span class="benzer-yemek-tarifi-ekleyen">Ekleyen: </span><br />
<span class="benzer-yemek-tarifi-izlenme">İzlenme: </span>
</div>
<% } %>

ASP.Net MVC2 Custom Templates Loading via Ajax and Model Updating

I have a view model with a collection of other objects in it.
public ParentViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<ChildViewModel> Child { get; set; }
}
public ChildViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
}
In one of my views I pass in a ParentViewModel as the model, and then use
<%: Html.EditorFor(x => x) %>
Which display a form for the Id and Name properties.
When the user clicks a button I call an action via Ajax to load in a partial view which takes a collection of Child:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Child>>" %>
<%: Html.EditorFor(x => x) %>
which then uses the custom template Child to display a form for each Child passed in.
The problem I'm having is that the form created by the Child custom template does not use the naming conventions used by the DefaultModelBinder.
ie the field name is (when loaded by Ajax):
[0].FirstName
instead of:
Child[0].FirstName
So the Edit action in my controller:
[HttpPost]
public virtual ActionResult Edit(int id, FormCollection formValues)
{
ParentViewModel parent = new ParentViewModel();
UpdateModel(parent);
return View(parent);
}
to recreate a ParentViewModel from the submitted form does not work.
I'm wondering what the best way to accomplish loading in Custom Templates via Ajax and then being able to use UpdateModel is.
Couple of things to start with is that you need to remember the default ModelBinder is recursive and it will try and work out what it needs to do ... so quite clever. The other thing to remember is you don't need to use the html helpers, actual html works fine as well :-)
So, first with the Model, nothing different here ..
public class ParentViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public List<ChildViewModel> Child { get; set; }
}
public class ChildViewModel
{
public int Id { get; set; }
public string FirstName { get; set; }
}
Parent partial view - this takes an instance of the ParentViewModel
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ParentViewModel>" %>
<h2>Parent</h2>
<%: Html.TextBox("parent.Name", Model.Name) %>
<%: Html.Hidden("parent.Id", Model.Id) %>
<% foreach (ChildViewModel childViewModel in Model.Child)
{
Html.RenderPartial("Child", childViewModel);
}
%>
Child partial view - this takes a single instance of the ChildViewModel
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<ChildViewModel>" %>
<h3>Child</h3>
<%: Html.Hidden("parent.Child.index", Model.Id) %>
<%: Html.Hidden(string.Format("parent.Child[{0}].Id", Model.Id), Model.Id)%>
<%: Html.TextBox(string.Format("parent.Child[{0}].FirstName", Model.Id), Model.FirstName) %>
Something to note at this point is that the index value is what is used for working out the unique record in the list. This does not need to be incremental value.
So, how do you call this? Well in the Index action which is going to display the data it needs to be passed in. I have setup some demo data and returned it in the ViewData dictionary to the index view.
So controller action ...
public ActionResult Index()
{
ViewData["Message"] = "Welcome to ASP.NET MVC!";
ViewData["Parent"] = GetData();
return View();
}
private ParentViewModel GetData()
{
var result = new ParentViewModel
{
Id = 1,
Name = "Parent name",
Child = new List<ChildViewModel>
{
new ChildViewModel {Id = 2, FirstName = "first child"},
new ChildViewModel {Id = 3, FirstName = "second child"}
}
};
return result;
}
In the real world you would call a data service etc.
And finally the contents of the Index view:
<form action="<%: Url.Action("Edit") %>" method="post">
<% if (ViewData["Parent"] != null) { %>
<%
Html.RenderPartial("Parent", ViewData["Parent"]); %>
<% } %>
<input type="submit" />
</form>
Saving
So now we have the data displayed how do we get it back into an action? Well this is something which the default model binder will do for you on simple data types in relatively complex formations. So you can setup the basic format of the action which you want to post to as:
[HttpPost]
public ActionResult Edit(ParentViewModel parent)
{
}
This will give you the updated details with the original ids (from the hidden fields) so you can update/edit as required.
New children through Ajax
You mentioned in your question loading in custom templates via ajax, do you mean how to give the user an option of adding in another child without postback?
If so, you do something like this ...
Add action - Need an action which will return a new ChildViewModel
[HttpPost]
public ActionResult Add()
{
var result = new ChildViewModel();
result.Id = 4;
result.FirstName = "** to update **";
return View("Child", result);
}
I've given it an id for easy of demo purposes.
You then need a way of calling the code, so the only view you need to update is the main Index view. This will include the javascript to get the action result, the link to call the code and a target HTML tag for the html to be appended to. Also don't forget to add your reference to jQuery in the master page or at the top of the view.
Index view - updated!
<script type="text/javascript">
function add() {
$.ajax(
{
type: "POST",
url: "<%: Url.Action("Add", "Home") %>",
success: function(result) {
$('#newchild').after(result);
},
error: function(req, status, error) {
}
});
}
</script>
<form action="<%: Url.Action("Edit") %>" method="post">
<% if (ViewData["Parent"] != null) { %>
<%
Html.RenderPartial("Parent", ViewData["Parent"]); %>
<% } %>
<div id="newchild"></div>
<br /><br />
<input type="submit" /> add child
</form>
This will call the add action, and append the response when it returns to the newChild div above the submit button.
I hope the long post is useful.
Enjoy :-)
Hmm... i personally would recommend to use a JSON result, instead of a HTML result, that you fiddle in the page...
makes the system cleaner. and your postback working ;-)
I found another way to accomplish this which works in my particular situation.
Instead of loading in a partial via via Ajax that is strongly typed to a child collection like:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Child>>" %>
I created a strongly typed view to the parent type and then called EditorFor on the list like so:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<Parent>" %>
<%: Html.EditorFor(x => x.ChildList) %>
This then calls a Custom Display Template and the result is that all the HTML elements get named correctly and the Default Model binder can put everything back together.

Recursion in an ASP.NET MVC view

I have a nested data object for a set of items within categories. Each category can contain sub categories and there is no set limit to the depth of sub categories. (A file system would have a similar structure.) It looks something like this:
class category
{
public int id;
public string name;
public IQueryable<category> categories;
public IQueryable<item> items;
}
class item
{
public int id;
public string name;
}
I am passing a list of categories to my view as IQueryable<category>. I want to output the categories as a set of nested unordered list (<ul>) blocks. I could nest foreach loops, but then the depth of sub categories would be limited by the number of nested foreach blocks. In WinForms, I have done similar processing using recursion to populate a TreeView, but I haven't seen any examples of using recursion within an ASPX MVC view.
Can recursion be done within an ASPX view? Are there other view engines that include recursion for view output?
Create your own HtmlHelper extension method like so:
namespace System.Web.Mvc
{
public static class HtmlHelperExtensions
{
public static string CategoryTree(this HtmlHelper html, IEnumerable<Category> categories)
{
string htmlOutput = string.Empty;
if (categories.Count() > 0)
{
htmlOutput += "<ul>";
foreach (Category category in Categories)
{
htmlOutput += "<li>";
htmlOutput += category.Name;
htmlOutput += html.CategoryTree(category.Categories);
htmlOutput += "</li>";
}
htmlOutput += "</ul>";
}
return htmlOutput;
}
}
}
Funny you should ask because I actually created one of these just yesterday.
You could easily do it by having each <ul> list in a PartialView, and for each new list you need to start you just call Html.RenderPartial("myPartialName");.
So the Category PartialView could look like this:
<%# Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<IEnumerable<Category>>" %>
<% foreach(Category cat in ViewData.Model) { %>
<li><p><%= cat.name %></p>
<% if (cat.categories.Count > 0) {
Html.RenderPartial("Category", cat.Categories);
} %></li>
<% } %>
In your View, you simply send the "root" collection as the model for the partial view:
<% Html.RenderPartial("Category", ViewData.Model) %>
EDIT:
I had forgotten the second parameter to the Html.RenderPartial() call - of course the category has to be passed as the model.
Of course you are right about the DRY mistake I made - I have updated my code accordingly.
You can use helper methods.
#model Models.CategoryModel
#helper TreeView(List<Models.CategoryModel> categoryTree)
{
foreach (var item in categoryTree)
{
<li>
#if (item.HasChild)
{
<span>#item.CategoryName</span>
<ul>
#TreeView(item.ChildCategories)
</ul>
}
else
{
<span class="leaf #item.CategoryTreeNodeType.ToString()" id="#item._CategoryId">#item.CategoryName</span>
}
</li>
}
}
<ul id="categorytree">
<li>#Model.CategoryName
#TreeView(Model.ChildCategories)
</li>
</ul>
More info can be found on this link:
http://weblogs.asp.net/scottgu/archive/2011/05/12/asp-net-mvc-3-and-the-helper-syntax-within-razor.aspx
You can reuse html parts with lambdas
Example
public class Category
{
public int id;
public string name;
public IEnumerable categories;
}
<%
Action<IEnumerable<Category>> categoriesMacros = null;
categoriesMacros = categories => { %>
<ul>
<% foreach(var c in categories) { %>
<li> <%= Html.Encode(c.name)%> </li>
<% if (c.categories != null && c.categories.Count() > 0) categoriesMacros(c.categories); %>
<% } %>
</ul>
<% }; %>
<% var categpries = (IEnumerable<Category>)ViewData["categories"]; %>
<% categoriesMacros(categpries); %>

Resources