George Phillipson
George Phillipson

Reputation: 860

foreach loop within mvc model

I'm stuck on a problem trying to get a foreach block of code to work within an mvc controller and viewmodel.

What i'm trying to achieve is loop through the datetime values and if less than 60 seconds, show seconds. if more than 60 seconds but less than 1 hour show minutes. else show full datetime.

I can get the above to work, but it only displays the 1st record. I have tried putting foreach loops in various places but just cannot seem to get it to work.

Would appreciated a fresh pair off eyes to help with this.

public class MostRecentPostsViewModel
    {
        public List<MembersForumProperties> SelectMostRecentForumPosts { get; set; }
        public string DateAndTimeOfForumPosts                          { get; set; }
    }

    public class IsPostLessThanOneHour
    {
        public static string DisplayPostInMinutesOrSeconds(string displyMostRecentForumPosts)
        {
            string displayTime = string.Empty;

            //foreach (var postTime in mv.SelectMostRecentForumPosts)
            //{
            //    dte = postTime.ForumMemberDateTimePostedPost;
            //}

            DateTime dtn = DateTime.Now;
            DateTime timeOfPost = Convert.ToDateTime(displyMostRecentForumPosts);

            TimeSpan ts = dtn - timeOfPost;
            if (ts.TotalSeconds > 0 && ts.TotalSeconds < 60)
            {
                displayTime = "about " + ts.Seconds + " seconds ago";
            }
            else if (ts.TotalSeconds > 61 && ts.TotalSeconds < 3600)
            {
                displayTime = "about " + ts.Minutes + " minutes ago";
            }
            else
            {
                displayTime = displyMostRecentForumPosts;
            }
            return displayTime;
        }
    }

Controller

public PartialViewResult MostRecentMembersPosts()
        {
            var displyMostRecentForumPosts = _imf.DisplayMostRecentForumPosts().ToList();
            var loopThroughDateTimes       = displyMostRecentForumPosts.ToList();
            var test = "";
            foreach (MembersForumProperties t in loopThroughDateTimes)
            {
                test = t.ForumMemberDateTimePostedPost;
            }

            var membersMostRecentPost = new MostRecentPostsViewModel
            {
              SelectMostRecentForumPosts = displyMostRecentForumPosts,

              DateAndTimeOfForumPosts = IsPostLessThanOneHour.DisplayPostInMinutesOrSeconds(test)
            };

            return PartialView("pvMostRecentMembersPost",membersMostRecentPost);
        }

Upvotes: 0

Views: 2023

Answers (1)

James
James

Reputation: 82096

Why not just send the dates down as is and use a JS plugin like TimeAgo e.g.

public PartialViewResult MostRecentMembersPosts()
{
    return PartialView("pvMostRecentMembersPost", _imf.DisplayMostRecentForumPosts().ToList());
}

Then in your view

@model IEnumerable<MemberForumProperties>

<!-- Head section would need to be defined in your master page first -->
@section Head {
    <script src="jquery.timeago.js" type="text/javascript"></script>
    <script type="text/javascript">
        $.ready(function() {
            $("abbr.timeago").timeago();
        });
    </script>
}

@foreach (var m in Model)
{
    <abbr class="timeago" title='@m.ForumMemberDateTimePostedPost.ToString("s")' />   
}

TimeAgo will take care of converting your DateTime values into a fuzzy timestamp.


The Problem

If you don't want to go for the client-side approach, then to fix your current server-side issue you need to send down a list of relative times, at the minute you only appear to be sending down the last relative time i.e.

var test = "";
foreach (MembersForumProperties t in loopThroughDateTimes)
{
    test = t.ForumMemberDateTimePostedPost;
}
// test now contains the date/time of the last item in the `loopThroughDateTimes` list

var membersMostRecentPost = new MostRecentPostsViewModel
{
    SelectMostRecentForumPosts = displyMostRecentForumPosts,

    DateAndTimeOfForumPosts = IsPostLessThanOneHour.DisplayPostInMinutesOrSeconds(test)
};
// DateAndTimeOfForumPosts only contains the relative string for the last date/time

Your current setup just appears a bit messy & cluttered and not very readable.

The Solution

To tidy it up a bit here's what I would do

public static class DateTimeExt
{
    public static string ToRelativeTime(this DateTime value)
    {
        // you could move the entire implementation of `DisplayPostInMinutesOrSeconds` to here
        return IsPostLessThanOneHour.DisplayPostInMinutesOrSeconds(value);
    }
}
...

public PartialViewResult MostRecentMembersPosts()
{
    return PartialView("pvMostRecentMembersPost", _imf.DisplayMostRecentForumPosts().ToList());
}

And then in your view

@model IEnumerable<MemberForumProperties>

@foreach (var props in Model)
{
    <p>@props.ForumMemberDateTimePostedPost.ToRelativeTime()</p>   
}

Upvotes: 2

Related Questions