I'm trying to group items in razor view by there id and put them all in one div
What I did put each one in a div .
<div class="tab-content" id="myTabContent">
#foreach (var item in Model)
{
<div class="tab-pane fade active in" id="genreTab ">
if (item.GenreId == 1)
{
#item.GenreId
}
</div>
if (item.GenreId == 2)
{
<div class="tab-pane fade " style="background-color:red;" id="genreTab ">
#item.GenreId
</div>
}
}
</div>
The classes in short:
public class Genre
{
public int GenreId { get; set; }
public string GenreName { get; set; }
public List<TakeAway> TakeAwys { get; set; }
}
public class TakeAway
{
public int TakeAwayId { get; set; }
public int GenreId { get; set; }
public virtual Genre genre { get; set; }
}
Your best bet is to loop over your genres instead of your items, if possible. You can accomplish this by grouping the items in your model by genres.
Then, loop over your genres in your view, with an inner loop of your items within the current genre.
Something like this:
#foreach (var genre in Model.Genres)
{
<div class="tab-pane fade active in" id="genreTab ">
#foreach (var item in genre.Items)
{
#item.SomeValueHere
}
</div>
}
Alternatively, if you are forced to receive your items flat like your OP, as much as I hate doing code like this in the view, using LINQ to group them in your view may be the lesser of the evils:
#foreach (var genre in Model.GroupBy(i => i.GenreId).Select(i => i.Key))
{
var innerGenre = genre; //to prevent modifed closure
<div class="tab-pane fade active in" id="genreTab ">
#foreach (var item in Model.Where(i => i.GenreId == innerGenre))
{
#item.SomeValueHere
}
</div>
}
An ID (genreTab) should be unique. If you want all in one div, you have to order them first.
When all are ordered, do this:
var lastId = 0;
<div class="tab-pane fade " style="background-color:red;" id="genreTab-#item.GenreId">
#foreach (var item in Model)
{
if (#item.GenreId != lastId)
{
</div><div class="tab-pane fade " style="background-color:red;" id="genreTab-#item.GenreId">
}
#item.GenreId
lastId = #item.GenreId;
}
</div>
Syntax may be wrong, I don't know razor syntax.
Related
(Reposted question, since the other one was put on hold and then edited but not reopened)
I have a problem with showing comment replies in my comment section on my website. I have made it so there is a Original Comment and that comment can have subcomment (replies) and the way I have set up my code it does work, but if there are 2 original comments and 1 reply on in one section, then it shows the reply og both of them, even though I've coded it to only show on a specific original comment.
Comment model:
namespace ComicbookWebpage.Models
{
public class ComicComment
{
public int Id { get; set; }
public string Comment { get; set; }
public DateTime Posted { get; set; }
public string UserId { get; set; }
public virtual ApplicationUser User { get; set; }
public int ComicId { get; set; }
public Comic Comic { get; set; }
public List<SubComicComment> SubComicComments { get; set; }
}
}
SubComment model (reply):
namespace ComicbookWebpage.Models
{
public class SubComicComment
{
public int Id { get; set; }
public string CommentText { get; set; }
public DateTime Posted { get; set; }
public SubComicComment() {
Posted = DateTime.Now;
}
public string UserId { get; set; }
public ApplicationUser User { get; set; }
public int ComicId { get; set; }
public Comic Comic { get; set; }
public int OriginalCommentId { get; set; }
public ComicComment ComicComment { get; set; }
}
}
Here's my viewmodel I use for all my data (vm):
namespace ComicbookWebpage.Models.ViewModels
{
public class ComicVM
{
public Comic Comic { get; set; }
public Series Series { get; set; }
public List<ComicComment> ComicComments { get; set; }
public List<SubComicComment> SubComicComments { get; set; }
}
}
So as you can see there is an "OriginalCommentId" in my subcomments table, so that I can tell my subcomments what original comment they belong to, so they're only shown under that specific comment. But the problem is like I said above that it shows my subcomment under 2 different original comments on the same page, if the page has 2 original comments, here's an image:
(Image) Comments in view (Browser SS)
On the right side of every comment, you can see an ID, it's the ID that the comment has and you can clearly see that the ID 9 has a subcomment with ID 2, which is totally wrong according to my coding. Because I'm telling my list to render the data where the original comment id is the same as subcomment's OriginalCommentId, so they should both have ID 9, but the subcomment has ID 2 for some reason...
Here's the controller code (Look at vm.SubComicComments):
public ActionResult Comic(int id)
{
ComicVM vm = new ComicVM();
vm.Comic = db.Comics.Include(m => m.Series).Where(m => m.Id == id).FirstOrDefault();
vm.Series = db.Series.FirstOrDefault();
vm.ComicComments = db.ComicComments.Where(m => m.Comic.Id == id).ToList();
vm.SubComicComments = db.SubComicComments.Where(m => m.ComicId == id && m.ComicComment.Id == m.OriginalCommentId).ToList();
db.Users.ToList();
return View(vm);
}
And here's the view code:
#using Microsoft.AspNet.Identity
#using System.Data.Entity;
#model ComicbookWebpage.Models.ViewModels.ComicVM
#{
ViewBag.Title = #Model.Comic.Title;
}
<a class="btn btn-default" href="/Series/Details/#Model.Comic.SeriesId"><i class="glyphicon glyphicon-menu-left"></i> Back</a>
<hr />
<h5><b>Title:</b> #Model.Comic.Title</h5>
<h5><b>Series:</b> #Model.Comic.Series.Title</h5>
<h5><b>Pages:</b> #Model.Comic.PageAmount</h5>
<hr />
<h4><i class="glyphicon glyphicon-comment"></i> Leave a comment:</h4>
<br />
#if (User.Identity.IsAuthenticated)
{
<div class="col-sm-1">
<div class="thumbnail">
<img class="img-responsive user-photo" src="https://ssl.gstatic.com/accounts/ui/avatar_2x.png">
</div><!-- /thumbnail -->
</div><!-- /col-sm-1 -->
<div class="col-sm-5">
<form action="/Series/Comic/#Model.Comic.Id" method="post">
<input type="hidden" name="Posted" value="#DateTime.Now" />
<input type="hidden" name="UserId" value="#User.Identity.GetUserId()" required />
<input type="hidden" name="ComicId" value="#Model.Comic.Id" />
<textarea class="form-control form-text" type="text" name="Comment" placeholder="Type your comment..." required></textarea>
<br />
<button type="submit" class="btn bg-dark">Send</button>
</form>
</div><!-- /col-sm-5 -->
}
else
{
<h5>You have to be logged in to post a comment.</h5>
<p>Click here to login</p>
}
<div class="row">
<div class="col-md-12">
#if (Model.ComicComments.Count > 0)
{
<h4>(#Model.ComicComments.Count) Comments:</h4>
}
else
{
<h4>0 Comments:</h4>
<p>There are currently no comments posted on this comic book.</p>
}
</div>
</div>
#foreach (var Comment in Model.ComicComments.Where(m => m.ComicId == m.Comic.Id))
{
<div class="comments-container">
<ul id="comments-list" class="comments-list">
<li>
<div class="comment-main-level">
<!-- Avatar -->
<div class="comment-avatar"><img src="https://i9.photobucket.com/albums/a88/creaticode/avatar_1_zps8e1c80cd.jpg" alt=""></div>
<!-- Contenedor del Comentario -->
<div class="comment-box">
<div class="comment-head">
<h6 class="comment-name by-author">#Comment.User.UserName</h6>
<span>posted on #Comment.Posted.ToShortDateString()</span><i>ID: #Comment.Id</i>
</div>
<div class="comment-content">
#Comment.Comment
</div>
</div>
</div>
<!-- Respuestas de los comentarios -->
<ul class="comments-list reply-list">
#if (Model.SubComicComments.Count > 0)
{
foreach (var SubComment in Model.SubComicComments.Where(m => m.OriginalCommentId == m.ComicComment.Id))
{
<li>
<!-- Avatar -->
<div class="comment-avatar"><img src="https://i9.photobucket.com/albums/a88/creaticode/avatar_2_zps7de12f8b.jpg" alt=""></div>
<!-- Contenedor del Comentario -->
<div class="comment-box">
<div class="comment-head">
<h6 class="comment-name">#SubComment.User.UserName</h6>
<span>posted on #SubComment.Posted.ToShortDateString()</span><i>ID: #SubComment.OriginalCommentId</i>
</div>
<div class="comment-content">
#SubComment.CommentText
</div>
</div>
</li>
}
}
</ul>
</li>
</ul>
</div>
}
If you guys can figure out what the heck is wrong here, I would appreciate it. To me the code is pretty logical and should work, but it doesn't, and I've tried so many things but no luck.
Thank you in advance.
For your SubComments foreach statement:
foreach (var SubComment in Model.SubComicComments.Where(m => m.OriginalCommentId == m.ComicComment.Id))
Should be:
foreach (var SubComment in Model.SubComicComments.Where(m => m.OriginalCommentId == Comment.Id))
No? You want to check SubComment.OriginalCommentId against the id in the Comment variable declared in your enclosing Comments iteration.
As an aside, in your first foreach statement, I don't think the where clause is doing anything:
#foreach (var Comment in Model.ComicComments.Where(m => m.ComicId == m.Comic.Id))
ComicID == Comid.Id should always be true as long as your includes have loaded...
I can get my Products model to my view ok. but I need to pass it in a ViewModel so I can interact with data from several models. When I bind my view to ProductPageViewModel then I get the "no public definition for GetEnumerator" error. I have tried all manner of IEnumerable options and cannot find the right combination.
I included controller and view that work when the view is bound to the model.
The full error is
CS1579: foreach statement cannot operate on variables of type JaniesWebLive.ViewModel.ProductPageViewModel' because
JaniesWebLive.ViewModel.ProductPageViewModel' does not contain a public definition for 'GetEnumerator'
Triggered at #foreach (var item in Model)
Products.cs
public class Products
{
[Key]
public int WpId { get; set; }
public string Category { get; set; }
public string WpProductId { get; set; }
public string ProdDescShort { get; set; }
public string ProdDescLong { get; set; }
public string ProductMedium { get; set; }
public decimal? Price1 { get; set; }
}
ProductPageViewModel.cs
public class ProductPageViewModel
{
public IEnumerable<Products> Products { get; set; }
public Contact Contacts { get; set; }
public string Message { get; set; }
/*more models to be added */
}
ProductsController.cs
public class ProductsController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
public ActionResult ShortList(string prodname)
{
var products = db.DbProducts.Where(m => m.Category == "homepage");
var model = new ViewModel.ProductPageViewModel
{
Products = products,
Message = "Thanks for your business! "
/* more models to be added */
};
return View(model);
}
}
ShortList.cshtml
#model IEnumerable<JaniesWebLive.ViewModel.ProductPageViewModel>
#foreach (var item in Model)
{
<div class="row">
<div class="col-md-4 col-sm-6 col-xs-12">
<p><img class="product-image" src=#Html.DisplayFor(modelItem => item.ProductMedium) /></p><br />
<h3>#Html.DisplayFor(modelItem => item.WpProductId)</h3>
<h5>#Html.DisplayFor(modelItem => item.Price1)</h5>
<h6>#Html.DisplayFor(modelItem => item.ProdDescShort)</h6>
<p class="text-center">#Html.DisplayFor(modelItem => item.ProdDescLong)</p>
<p>
<button class="text-right btn btn-link">SHORT LIST</button>
</p>
</div>
</div>
}
Working controller and view
public ActionResult LongList(string prodname)
{
var model = db.DbProducts.Where(m => m.Category == "homepage");
return View(model);
}
LongList.cshtml
#model JaniesWebLive.Models.Products
#foreach (var item in Model)
{
<div class="row">
<div class="col-md-4 col-sm-6 col-xs-12">
<p><img class="product-image" src=#Html.DisplayFor(modelItem => item.ProductMedium) /></p>
<h3>#Html.DisplayFor(modelItem => item.WpProductId)</h3>
<h5>#Html.DisplayFor(modelItem => item.Price1)</h5>
<h6>#Html.DisplayFor(modelItem => item.ProdDescShort)</h6>
<p class="text-center">#Html.DisplayFor(modelItem => item.ProdDescLong)</p>
<p>
<button class="text-right btn btn-link">LONG LIST</button>
</p>
</div>
</div>
}
you need to change the view to something like
#model JaniesWebLive.ViewModel.ProductPageViewModel
#foreach (var item in Model.Products )
{
<div class="row">
<div class="col-md-4 col-sm-6 col-xs-12">
<p><img class="product-image" src=#Html.DisplayFor(modelItem => item.ProductMedium) /></p><br />
<h3>#Html.DisplayFor(modelItem => item.WpProductId)</h3>
<h5>#Html.DisplayFor(modelItem => item.Price1)</h5>
<h6>#Html.DisplayFor(modelItem => item.ProdDescShort)</h6>
<p class="text-center">#Html.DisplayFor(modelItem => item.ProdDescLong)</p>
<p>
<button class="text-right btn btn-link">SHORT LIST</button>
</p>
</div>
</div>
}
since upr view model is a single object which contain a list property you need to itterate the property not the whole model
I am trying to post back the changes to the nested list of checkboxes for Groups and their Users but keep getting my list Count = 0 when it posts. Right now, there are no groups within groups, but I would still like to make this recursive if we move towards that in the future.
I have a hierarchical IList of GroupsUsers attached to my Activity Model as such:
Activity:
public class Activity
{
public int ActivityId { get; set; }
public string Name { get; set; }
public string Path { get; set; }
public string Description { get; set; }
public Nullable<int> ParentId { get; set; }
public IList<GroupsUsers> Hierarchy { get; set; }
}
GroupsUsers:
public class GroupsUsers
{
public Guid? Guid { get; set; }
public string Name { get; set; }
public bool IsAllowed { get; set; } = false;
public IList<GroupsUsers> Children { get; set; } = new List<GroupsUsers>();
}
I have tried EditorFor, Partial View, and Helper but am having no luck with any of them posting back the Hierarchy. My Model.Hierarchy is posting back with Count = 0.
Here's my current attempt:
Main View (watered down):
#model MyProject.Models.Activity
#using (Html.BeginForm())
{
<!-- Activity stuff -->
<ul style="list-style:none;">
#for (var i = 0; i < Model.Hierarchy.Count(); i++)
{
#Html.EditorFor(model => model.Hierarchy[i])
}
</ul>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
}
Current Attempt. GroupsUsers.cshtml:
#model MyProject.Models.GroupsUsers
<li>
#Html.HiddenFor(model => model.Guid)
#Html.HiddenFor(model => model.Name)
#Html.CheckBoxFor(model => model.IsAllowed, new { #class = "groupsusers-checkbox", #style = "margin-right:5px; cursor:pointer;", #value = Model.Guid.ToString() }) #Html.LabelFor(model => model.IsAllowed, Model.Name, new { #class = "build-checkbox-label", #style = "font-weight:normal; margin-top:-2px;" })
#if (Model.Children.Any())
{
<ul style="list-style:none;">
#for (var i = 0; i < Model.Children.Count(); i++)
{
#Html.EditorFor(model => model.Children[i])
}
</ul>
}
</li>
I'm looking for my list of checkboxes to display as a list hierarchy recursively and post Model.Hierarchy back properly.
Any help would be appreciated... I only included Attempt #2 and #3 in case I was close to having it correct.
I have problems to send back data from view to controller. I'm quite new to MVC and I can't figure it out what is the problem.
This is the view:
#model IEnumerable<OnlineCarStore.Models.CategoriesVM>
<div class="container">
<div class="row">
#using (Html.BeginForm("SubCategory", "Product"))
{
<div class="list-group col-sm-3" style="width:280px;">
#{var selected = string.Empty;
if (#HttpContext.Current.Session["selectedCar"] == null)
{
selected = string.Empty;
}
else
{
selected = #HttpContext.Current.Session["selectedCar"].ToString();
}
foreach (var c in Model)
{
<a href="#Url.Action("SubCategory", "Product", new { selected = selected, id = #c.ID, category = #c.CategoryName })" id="link" class="list-group-item">
<span> #c.CategoryName</span>
</a>
for (int i = 0; i < c.Childrens.Count; i++)
{
#Html.HiddenFor(x => c.Childrens[i].Item)
#Html.HiddenFor(x => c.Childrens[i].Children)
}
}
}
This is the view model for the data that I need:
public class CategoriesVM
{
public int ID { get; set; }
public int AtpID { get; set; }
public string CategoryName { get; set; }
public List<Helpers.TreeItem<Categories>> Childrens { get; set; }
}
This is in the controller:
public ActionResult SubCategory(IEnumerable<OnlineCarStore.Models.CategoriesVM> Model)
{
. In the Model parameter I need all the data that the CategoriesVM contains, but the Model parameter is always null.
Can you please advise what I'm doing wrong? What I'm missing?
Thanks!
You cannot (and should not) pass all the properties of your Category object via a link click! It works only when your object is lean-flat with very few properties. When your object is complex, this is not ideal!
You should simply pass the unique Id (category id) to the next action method and in which you use this id to query the needed data and use that.
I also noticed that you are setting the same id value to the link in the loop. It will produce multiple anchor tag with same Id value. That is invalid HTML. So let's remove that.
<a href="#Url.Action("SubCategory", "Product", new { id = #c.ID })"
class="list-group-item">
<span> #c.CategoryName</span>
</a>
Now in your SubCategory action method
public ActionResult SubCategory(int id)
{
//using the id, get the data needed (may be the category & subcategories)
// to do : Return something
}
I am very new to MVC dot net. For an e-commerce app I need to populate category and subcategory. By clicking on subcategory all product should display based on selected subcategory. But I don't how to solve this one..
Here is my Model
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
}
public class SubCategory
{
public int SubCategoryId { get; set; }
public string SubCategoryName { get; set; }
public int CategoryId { get; set; }
}
Subcategory Table in database:
SubcategoryId SubCategoryName CategoryId
1 NIKE 1
2 ADIDAS 1
3 FENDI 2
4 GUCCI 2
Controller:
CategoryManager manager=new CategoryManager();
public ActionResult Index()
{
ViewBag.Categories = manager.GetCategories();
ViewBag.SubCategories = manager.GetSubCategories();
return View();
}
View for Controller:
#using EcommerceApp.Models;
#{
List<Category> allCategories = null;
allCategories= ViewBag.Categories;
//...Code for Subcategory....//
}
#if (allCategories!= null)
{
foreach (var catagories in allCategories)
{
<div class="panel panel-default">
<div class="panel-heading">
<h4 class="panel-title">
<a data-toggle="collapse" data-parent="#accordian" href="##catagories.CategoryId
">
<span class="badge pull-right"><i class="fa fa-plus"></i></span>
#catagories.CategoryName
</a>
</h4>
</div>
<div id="#catagories.CategoryId" class="panel-collapse collapse">
<div class="panel-body">
<ul>
#*<li>....Code For Subcategory...</li>*#
</ul>
</div>
</div>
</div>
}
}
Gateway For SUbCategory:
public List<SubCategory> GetSubCategories()
{
List<SubCategory> subCategoryList = new List<SubCategory>();
SqlConnection connection = new SqlConnection(ConnectionString);
string query = "SELECT * FROM SubCategory";
SqlCommand command = new SqlCommand(query, connection);
connection.Open();
SqlDataReader reader = command.ExecuteReader();
while (reader.Read())
{
SubCategory subCategory = new SubCategory();
subCategory.CategoryId = (int)reader["CategoryId"];
subCategory.SubCategoryName = reader["SubCategoryName"].ToString();
subCategory.SubCategoryId = (int) reader["SubCategoryId"];
subCategoryList.Add(subCategory);
}
return subCategoryList;
}
This code populates Categories but I don't know how to populate Corresponding Subcategories and get product based on subcategory ID. What do I need to write or change in Controller, Model and View?