MVC 4 TreeView Menu - asp.net-mvc

I tried to follow this, as it was quoted as an example in many places:
http://weblogs.asp.net/mikebosch/archive/2008/11/25/hierarchical-treeview-with-asp-net-mvc-jquery.aspx
and have come up with the following (a few alterations due to me using mvc4 not 2)
In the controller class:
public ActionResult Index()
{
MenuDBContext db = new MenuDBContext();
ViewData["AllMenu"] = db.Menus.ToList();
return View(db.Menus.ToList().Where(c => c.PId == null));
}
The view class:
#{
ViewBag.Title = "Index";
}
#model IEnumerable<Geo.Models.Menu>
<h2>Index</h2>
#foreach (var item in Model)
{
<li>
#item
#{var children = ViewData["AllMenu"].Where(c => c.PId == item.Id);}
#if (children.Count() > 0)
{
<ul>
#{Html.RenderPartial("ItemControl", children);}
</ul>
}
</li>
}
I can't for the life of me work out why I can't use .Where on ViewData["AllMenu"] or .Count() on children. Any tips on where I am going wrong would be fantastic.

You need to cast ViewData["AllMenu"] as IEnumerable<
var children = (ViewData["AllMenu"] as IEnumerable<GeomantApp.Models.Menu>).Where(c => c....
ViewData is Dictionary<string,object> so when you try and get a property from that dictionary, ASP.NET has no way of knowing what it is before hand so you get compiler errors if you don't cast your object first.

Related

Asp.Net MVC return list to view

I am trying to return a list to my view. I can return it with #viewbag but i only get one entry from it .
If i try to do return view(items) I get exception issues. what should I do ?
here is my controller
foreach (var movie in item)
{
var items = _db.Movies.Where(s => s.imdbID.Equals(movie.Movieid)).ToList();
ViewBag.Movies = items;
return View(items);
}
Here is my view
#foreach (var item in ViewBag.Movies)
{
<p> #item.Title </p>
}
First of all you must not return View() inside a loop.
What is the meaning there ?
var items = new List<Movies>();
foreach (var movie in item)
{
items = items.Add(_db.Movies.Where(s =>
s.imdbID.Equals(movie.Movieid)).ToList());
}
return View(items);
And if you are returning the list why do you need that ViewBag.
ViewBag is needed when you dont want to include any other model in Dto you are passing. So if you are passing list of type Movies and for example you need another list of different type you pass the other one on ViewBag.
Do this on your View:
#model List<Movies>
#foreach(var item in Model)
{
<p> #item.Title </p>
}
Move your return outside the loop and remove the ViewBag, it looks like your controller is wrong, and some part of the View.
I Would also change the Where to FirstOrDefault, because you expect only 1 Movie to be found in the db.
And remove the .ToList(), because that does nothing right now.
like this:
var items = new List<Movies>();
foreach (var movie in item)
{
items.Add(_db.Movies.FirstOrDefault(s => s.imdbID.Equals(movie.Movieid)));
}
return View(items);
Also change your view to this:
#model IEnumerable<namespace.Models.movies>
#foreach(var item in Model)
{
<p> #item.Title </p>
}
You should use your model in the view, not the Viewbag, because right now, the (items) does nothing.
Also, look up how to add to a list in c#, it feels like you have some more to learn there, you can check here:
https://www.jennerstrand.se/add-object-to-list-in-c-sharp/
In view, you have to import the model of movies.
For example in view,
#model IEnumerable<projectName.models.movies>
#foreach(var item in Model)
{
<p> #item.Title </p>
}

Is it possible to add where clause in html.partial

i have html.partial in my html markup which is getting and displaying all the records from database. but i want to change it to selected records.. i mean i want to put where clause in html.partial.. is it possible to add where clause in partial and filter the records?
my html markup is like this
#Html.Partial("ListProductPartial", Model.Data.OrderByDescending(o => o.Id))
i am very much new to asp.net mvc. i am using pre defined code and want to understand the code. i hope you guys will help me to resolve this issue..
Depending on your model, this should work (keeping the OrderByDescending):
#Html.Partial("ListProductPartial", Model.Data.Where(o => o.Name == "FilterText").OrderByDescending(o => o.Id))
I do not recommend this style but you can try this sample;
Partial View
#model List<WebApplication4.Models.WebModelData>
#{
foreach (var item in Model)
{
#Html.Raw(item.Value)
}
}
Call to partial
#Html.Partial("PartialView", Model.Data.Where(o => o.Id > 5).ToList())
Controller:
public ActionResult Index()
{
List<Student> ob = new List<Student>()
{
new Student{ id=1, Name="x"},
new Student{ id=2, Name="y"},
};
return View(ob);
}
Index:
#model List<WebApplication15.Controllers.Student>
#{
ViewBag.Title = "Index";
}
#Html.Partial("Name",Model.OrderByDescending(x=>x.id))
<h2>Index</h2>
Partial View:
#model IEnumerable<WebApplication15.Controllers.Student>
#foreach (var student in Model)
{
<li>#student.id</li>
<li>#student.Name</li>
}

Send list<AnonymousType> from controller to view in ASP.Net MVC

Controller action method-
public ActionResult Index()
{
var todaysTarget = from ra in db.Employee ...
select new { ra.RaCode, ra.TargetQuantity };
return View(todaysTarget.ToList());
}
Razor view-
#model List<object>
#foreach (var item in Model)
{
#:item.Name;
}
It gives me exception-
this dictionary requires a model item of type 'System.Collections.Generic.List`1[System.Object]'.
Any help?
Try in your view:
#model List<dynamic>
Or try in your return statement doing:
return View(todaysTarget.Cast<object>().ToList());
But if you do the latter, the item.Name statement will raise an error (type Object doesn't have a property of Name) which is why dynamic should get the job done.
This should work . I tried locally .
#model IEnumerable<dynamic>
<div>
<h1> Test</h1>
#foreach (var item in Model)
{
#item.Name;
}
</div>

How can I bind a IEnumerable sequence to a container with multiple columns?

I believe that I couldn't find a proper title to explain my problem but I think this is the best possible short explanation.
Please let me explain the details.
I want to show a list of my pictures on a page and using a #foreach loop on MVC 3.
Partial View of this list as below:
#model IEnumerable<Picture>
#foreach (var item in Model)
{
<a href="#item.PicId">
<img height="35px" style="padding-top:3px" src="ImageHandler.ashx?id=#item.PicId" id="pictureMy" />
</a>
}
As you may understand I am sending a list to this partialview and it is placing the pictures on a single column.
It is working without any problem but I want to show 3 pictures for each row but couldn't manage.
Any guidance will be very appreciated.
Thanks in advance for your helps.
You could group them by 3:
#model IEnumerable<Picture>
#foreach (var item in Model.Select((value, index) => new { value, index }).GroupBy(x => x.index / 3))
{
<div>
#foreach (var picture in item)
{
<a href="#picture.value.PicId">
<img height="35px" style="padding-top:3px" src="ImageHandler.ashx?id=#picture.value.PicId" id="pictureMy" />
</a>
}
</div>
}
But honestly this grouping is not something that should be done in the view. You should define a view model and then have your controller action perform the grouping and return the view model.
So let's start by defining our view models:
public class PictureViewModel
{
public int PicId { get; set; }
}
public class GroupedPicturesViewModel
{
public IEnumerable<PictureViewModel> Pictures { get; set; }
}
then the controller action:
public ActionResult Index()
{
// fetch the pictures from the DAL or something
IEnumerable<Picture> pictures = ...
// Now build the view model
var model = pictures
.Select((value, index) => new { value, index })
.GroupBy(x => x.index / 3)
.Select(x => new GroupedPicturesViewModel
{
Pictures = x.Select(p => new PictureViewModel
{
PicId = p.value.PicId
})
}
);
return View(model);
}
then the corresponding view:
#model IEnumerable<GroupedPicturesViewModel>
#Html.DisplayForModel()
then the corresponding display template for the GroupedPicturesViewModel type (~/Views/Shared/DisplayTemplates/GroupedPicturesViewModel.cshtml):
#model GroupedPicturesViewModel
<div>
#Html.DisplayFor(x => x.Pictures)
</div>
and finally the display template for the PictureViewModel type (~/Views/Shared/DisplayTemplates/PictureViewModel.cshtml):
#model PictureViewModel
<a href="#Model.PicId">
<img class="image" src="#Url.Content("~/ImageHandler.ashx?id=" + Model.PicId)" alt="" />
</a>
One final thing that's bugging me is this anchor. Looks ugly. Don't you think? Looks like spaghetti code.
Let's improve it by writing a custom, reusable HTML helper which will render those pictures:
public static class HtmlExtensions
{
public static IHtmlString Picture(this HtmlHelper<PictureViewModel> htmlHelper)
{
var anchor = new TagBuilder("a");
var picture = htmlHelper.ViewData.Model;
var id = picture.PicId.ToString();
var urlHelper = new UrlHelper(htmlHelper.ViewContext.RequestContext);
// You probably need another property on your view model here as this
// id is suspicious about href but since that's what you had in your
// original code I don't know what is your intent.
anchor.Attributes["href"] = id;
var image = new TagBuilder("img");
image.Attributes["alt"] = "";
image.Attributes["src"] = urlHelper.Content(
"~/ImageHandler.ashx?id=" + urlHelper.Encode(id)
);
image.AddCssClass("image");
anchor.InnerHtml = image.ToString();
return new HtmlString(anchor.ToString());
}
}
and then in the display template we will simply have:
#model PictureViewModel
#Html.Picture()
And that's pretty much it. No need to write loops. Everything works by convention.

In ASP.NET MVC, how can you bind several select lists to an IList<string> collection?

I have a model with a List<string> property. I want to present several select lists that bind to that property.
For example, supposed my model is named Favories, and I let the user select several favorite colors.
public class Favorites
{
public List<string> FavoriteColors { get; set;}
}
I tried binding using the indexes to the collection, but I ran into problems, most likely because FavoriteColors was empty. Here's the code that doesn't work (null exception):
#Html.DropDownListFor(m => m.FavoriteColors[0], ColorSelectList, "Select a color (required)")
#Html.DropDownListFor(m => m.FavoriteColors[1], ColorSelectList, "Select a color (optional)")
#Html.DropDownListFor(m => m.FavoriteColors[2], ColorSelectList, "Select a color (optional)")
I realize I could fix this a couple ways.
Populate FavoriteColors with 3 empty values. But this doesn't feel right since my model would have invalid data (empty values) that I'd have to workaround in a bunch of other places in my code.
Change my model so that I have 3 string properties (e.g. FavoriteColor1, FavoriteColor2, FavoriteColor3). Binding would be easier, but I'd still have to work around that deisgn with a bunch of code.
Is there a better way?
Here is a simple solution that will work for you using Razor and standard DropDownListFor<T> helpers.
All based on example data and files which you can change to suit your needs:
HomeController.cs
public class HomeController : Controller
{
public class FavoriteColorModel
{
public List<string> FavoriteColors { get; set; }
}
public ActionResult Index()
{
ViewBag.ColorList = new[]
{
"Blue",
"Red",
"Green",
"Orange"
};
var favoriteColors = new FavoriteColorModel()
{
FavoriteColors = new List<string>()
{
"Color1",
"Color2",
"Color3"
}
};
return View(favoriteColors);
}
[HttpPost]
public ActionResult Save(FavoriteColorModel model)
{
TempData["SelectedColors"] = model.FavoriteColors;
return RedirectToAction("Index");
}
}
Index.cshtml
#model MvcApplication4.Controllers.HomeController.FavoriteColorModel
#{
ViewBag.Title = "Index";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h2>Index</h2>
#if (TempData["SelectedColors"] != null)
{
<text>
You have selected the following colors:<br />
<ul>
#foreach (var color in TempData["SelectedColors"] as List<string>)
{
<li style="color:#color">#color</li>
}
</ul>
</text>
}
#using (Html.BeginForm("Save", "Home"))
{
#: Favorite colors:
for (var index = 0; index < Model.FavoriteColors.Count; index++)
{
#Html.DropDownListFor(model => model.FavoriteColors[index], new SelectList(ViewBag.ColorList))
}
<br />
<input type="submit" value="Save" />
}
Your selected colors will appear in a list element upon submit. You can control the amount of colors you wish to save by adding items to the Color1, Color2 array etc.
Peace.
This is how I would do it because I dont like the way MVC handles drop down lists.
foreach (var ColorArray in m.FavoriteColors)
{ %>
<select name='colors'>
<% foreach (var color in ColorArray)
{%>
<option><%= color.ToString() %></option>
<% { %>
</select>
}%>
You could hard code it to just the indexes you want but you get the general idea. Also this would allow you to put in null checks whereever you like to handle those cases selectively.

Resources