Reputation: 2012
I'm drawing a blank on this. I have two foreach loops that are creating div's and I'm trying to get 1 or two items from the 2nd foreach to display every 2 items from the first foreach.... here's the code..
@foreach (var stream in Model.LiveStreams)
{
<div id="divLiveStream" class="well-livestream well-sm">
<div class="row">
<div class="col-md-2">
<div class="ui-icon-image">
<img src="~/Images/placeholder.jpg" width="100%" />
</div>
</div>
<div class="col-md-10">
<div class="text-left row">
<div class="col-md-12">
@stream.UserName
</div>
<div class="col-md-12">
@stream.Status
</div>
</div>
</div>
</div>
</div>
}
@foreach (var post in Model.LivePosts)
{
<div id="divLivePost" class="well-liveposts well-sm">
<div class="row">
<div class="col-md-2">
<div class="ui-icon-image">
<img src="~/Images/placeholder.jpg" width="100%" />
</div>
</div>
<div class="col-md-10">
<div class="text-left row">
<div class="col-md-12">
@post.AspNetUser.UserName
</div>
<div class="col-md-12">
@post.PostDescription
</div>
</div>
</div>
</div>
</div>
}
So for further clarification, I'm trying to display 2 divLiveStreams, then display 2 divLivePost, and continue on with that pattern. I'm new to MVC so I'm not sure how to go about this and I'm drawing all kinds of blanks on this Friday.. Thanks in advance!
Edit: Here is my ViewModel.
public class LiveStreamViewModel
{
public IEnumerable<LiveStream> LiveStreams { get; set; }
public IEnumerable<tPost> LivePosts { get; set; }
}
Edit: Probably a dumb question, but I use my controller to return the model. Before I had my controller like below, how am I suppose to call the new ViewModel that you created in the controller? Here is my Controller.
public ActionResult LiveStream()
{
Service service = new Service();
LiveStreamViewModel model = new LiveStreamViewModel
{
LiveStreams = service.GetLiveStream(),
LivePosts = service.GetLivePosts()
};
if (TempData["Message"] != null) ViewBag.Message = TempData["Message"]; ViewBag.Header = "Success!";
return View(model);
}
}
And my data service.
public IEnumerable<LiveStream> GetLiveStream()
{
using (dboMyJeepTraderEntities context = new dboMyJeepTraderEntities())
{
return (from s in context.tStatusUpdates select new LiveStream
{
Status = s.Status,
UserName = s.AspNetUser.UserName
}).ToList();
}
}
public IEnumerable<tPost> GetLivePosts()
{
return (from p in _context.tPosts select p).ToList();
}
Upvotes: 0
Views: 102
Reputation: 85665
Well, so - yeah - doing it in the Controller
obviously makes sense. But, then again, Razor is just (mostly) C# so whatever you can do in one you can do in the other:
@{
var streamIndex = 0;
var postIndex = 0;
}
@while (streamIndex < Model.LiveStreams.Count() || postIndex < Model.LivePosts.Count()) {
@foreach (var stream in Model.LiveStreams.Skip(streamIndex).Take(2)) {
// html code
streamIndex++;
}
@foreach (var post in Model.LivePosts.Skip(postIndex).Take(2)) {
// html code
postIndex++;
}
}
Upvotes: 0
Reputation: 27904
You need one viewmodel, with the alternation happening with the hydration of the viewmodel.
public abstract class AbstractThing
{
public abstract string TheUserName { get; }
public abstract string TheDescription { get; }
}
public class LivePost : AbstractThing
{
public string UserName { get; set; }
public string PostDescription { get; set; }
public override string TheUserName
{
get { return this.UserName; }
}
public override string TheDescription
{
get { return this.PostDescription; }
}
}
public class LiveStream : AbstractThing
{
public string UserName { get; set; }
public string Status { get; set; }
public override string TheUserName
{
get { return this.UserName; }
}
public override string TheDescription
{
get { return this.Status; }
}
}
public class AlternatingThingsViewModel
{
public ICollection<AbstractThing> AbstractThings { get; private set; }
public AlternatingThingsViewModel(ICollection<LivePost> lps, ICollection<LiveStream> lss)
{
this.AbstractThings = new List<AbstractThing>();
/* this is not correct...here is where you would "two by two" add items to the this.AbstractThings in the order you want. the key is to have one collection exposed by the viewmodel */
if (null != lps)
{
foreach (AbstractThing at in lps)
{
this.AbstractThings.Add(at);
}
}
if (null != lss)
{
foreach (AbstractThing at in lss)
{
this.AbstractThings.Add(at);
}
}
}
}
Now you loop on the single collection
@foreach (var post in Model.AbstractThings)
{
<div id="divLivePost" class="well-liveposts well-sm">
<div class="row">
<div class="col-md-2">
<div class="ui-icon-image">
<img src="~/Images/placeholder.jpg" width="100%" />
</div>
</div>
<div class="col-md-10">
<div class="text-left row">
<div class="col-md-12">
@post.TheUserName
</div>
<div class="col-md-12">
@post.TheDescription
</div>
</div>
</div>
</div>
</div>
}
Below is a "one then other one" implementation...as long as the LivePost count is greater than the LiveStream. And no error checking. But gives you an idea.
public class AlternatingThingsViewModel
{
public ICollection<AbstractThing> AbstractThings { get; private set; }
public AlternatingThingsViewModel(ICollection<LivePost> lps, ICollection<LiveStream> lss)
{
this.AbstractThings = new List<AbstractThing>();
/* this is a "one by one" with no error checking if the counts are different */
IEnumerator<AbstractThing> livePostEnum = null == lps ? null : lps.GetEnumerator();
IEnumerator<AbstractThing> liveStreamEnum = null == lss ? null : lss.GetEnumerator();
if (null != liveStreamEnum)
{
liveStreamEnum.MoveNext();
}
if (null != livePostEnum)
{
while (livePostEnum.MoveNext() == true)
{
AbstractThing lpCurrent = livePostEnum.Current;
AbstractThing lsCurrent = null == liveStreamEnum ? null : liveStreamEnum.Current;
if (null != liveStreamEnum)
{
liveStreamEnum.MoveNext();
}
this.AbstractThings.Add(lpCurrent);
if (null != lsCurrent)
{
this.AbstractThings.Add(lsCurrent);
}
}
}
}
}
and some calling code.
static void Main(string[] args)
{
try
{
ICollection<LivePost> lps = new List<LivePost>();
lps.Add(new LivePost() { UserName = "LivePostUserName1", PostDescription = "LivePostDescription1" });
lps.Add(new LivePost() { UserName = "LivePostUserName2", PostDescription = "LivePostDescription2" });
lps.Add(new LivePost() { UserName = "LivePostUserName3", PostDescription = "LivePostDescription3" });
lps.Add(new LivePost() { UserName = "LivePostUserName4", PostDescription = "LivePostDescription4" });
ICollection<LiveStream> lss = new List<LiveStream>();
lss.Add(new LiveStream() { UserName = "LiveStreamUserName1", Status = "LiveStreamStatus1" });
lss.Add(new LiveStream() { UserName = "LiveStreamUserName2", Status = "LiveStreamStatus2" });
//lss.Add(new LiveStream() { UserName = "LiveStreamUserName3", Status = "LiveStreamStatus3" });
AlternatingThingsViewModel atmv = new AlternatingThingsViewModel(lps, lss);
int modCheckCount = 0;
foreach (AbstractThing at in atmv.AbstractThings)
{
Console.WriteLine("{0}, {1}", at.TheUserName, at.TheDescription);
if (++modCheckCount % 2 == 0)
{
Console.WriteLine("");
}
}
Upvotes: 3