Thorsten Westheider
Thorsten Westheider

Reputation: 10932

How to pass data for a link in a view model in ASP.NET MVC (Core)

Let's presume I have a view for a blog post and I need to come up with a view model for that view. The view displays

If these were just text elements, I'd go with

public PostViewModel
{
   public string AuthorName { get; set; }
   public DateTime Date { get; set; }
   public int NumberOfComments { get; set; }
   public IEnumerable<string> Tags { get; set; }
}

However, what if I wanted some of these to be links? Clicking on the author name would take me to the author's profile, clicking on comments would take me to the comments. Now this all of a sudden becomes more challenging.

What are my options here?

  1. Pass the actual (domain) models instead of just strings and numbers
  2. Pass the author's ID in order to create an ActionLink inside the view, same for comments (post ID)
  3. Create a view model for author and pass that instead of the domain model
  4. Create a view model for a link and use that whereever I need a link in the view

Out of these only option 4 seems viable, so

public ActionViewModel
{
   public string Action { get; set; }
   public string Controller { get; set; }
   public string Text { get; set; }
   public RouteValueDictionary RouteValues { get; set; }
}

and PostViewModel becomes

public PostViewModel
{
   public ActionViewModel AuthorName { get; set; }
   public DateTime Date { get; set; }
   public ActionViewModel NumberOfComments { get; set; }
   public IEnumerable<ActionViewModel> Tags { get; set; }
}

At this point I'm wondering why the framework wouldn't support such a common scenario out of the box. Am I missing something here or is this indeed the way to go?

EDIT: I added the Tags property to make it more clear why I consider option 2 to be problematic. I can't just have

public IEnumerable<string> Tags { get; set; }
public IEnumerable<int> TagIds { get; set; }

because there is no safe correlation between a tag name and its ID, so I'd have to introduce an object here anyway.

Upvotes: 1

Views: 2943

Answers (1)

Shyju
Shyju

Reputation: 218732

You can simply add a property for post id and another for author Id and use those.

public PostViewModel
{
   public int Id {set;get;}
   public int AuthorId { set;get;
   public string AuthorName { get; set; }
   public DateTime Date { get; set; }
   public int NumberOfComments { get; set; }
}

In your view

@model PostViewModel
<p>Post created by @Html.ActionLink(Model.AuthorName,"Details","User"
                                                        ,new { id=Model.AuthorId},null)</p>
<p>Total @Html.ActionLink(Model.NumberOfComments,"Comments","Post"
                                                   ,new { postId =Model.AuthorId},null)</p>

Assuming you have a Details action method in Usercontroller which accepts an id parameter and Comments action on PostController which accepts a postId parameter.

If you already have an User/Author view model, you can replace the AuthorId and AuthorName in your PostViewModel with that.

EDIT : As per the question edit.

if you want a collection of Tags, create another little view model for that and use a collection of that type as your property

Here i created a view model for Author as well as you need that in the Author details page (which goes from the author link)

public class BaseVm
{
  public int Id {set;get;}
  public string Name { set;get;}
}
public class AuthorVm : BaseVm
{
}
public class TagVm : BaseVm
{
}
public PostViewModel
{
   public int Id {set;get;}
   public AuthorVm Author { set;get;  
   public DateTime Date { get; set; }
   public int NumberOfComments { get; set; }
   public List<TagVm> Tags {set;get;}

   public PostViewModel()
   {
     this.Tags = new List<TagVm>();
     this.Author = new AuthorVm();
   }
}

Now in your view, you should access the author Id/Name like Model.Author.Id

Upvotes: 2

Related Questions