0

I am working on ASP.NET Core web site using Razor Pages instead of MVC.

I faced a situation where I have to implement a shared component which can be used in different pages. The component is - Simple comments thread. On different pages signed users can send their comments.

The component should consist of 2 parts:

  1. Comments List - this is the list of comments which can be easily implemented with either ViewComponent or Partial Page;
  2. Add comment control - this is textarea and submit button which allow user to send their own comment.

What I want to achieve is to use ViewComponent or Partial page or some other technique to put some markup with initial parameters on any page to enable this comments functionality without copy/pasting same code from page to page.

And I have a few issues with this.

As I already mentioned, ViewComponent can be used to show the list of comments on any page just by adding the following markup:

@await Component.InvokeAsync("Comments", new { type="NewsItem", id="@Model.Item.ID" })

So CommentsViewComponent will call ef.core DBContext to load comments for defined type and id. This works perfect. But the issue start to happen when I need to send posts from ViewComponent's markup and handle these posts.

It is planned to have 3 possible post calls:

  1. Add new comment
  2. Delete existing comment
  3. Edit existing comment

The first possible approach is to define 3 handlers on NewsItem page and call them using tag-helper from ViewComponent. But then i would have to define 3 same handlers on any other page where i would need the same functionality.

Another approach which I was thinking about is to define some fake PageModel which would contain these 3 handlers and ViewComponent would post to this page using Ajax. The only complication here is that after doing these posts I need to force ViewComponent to rerender itself since Comments were changed (deleted, added or edited).

So as a result the component would contains of the following parts:

  1. ViewComponent to show necessary markup
  2. JavaScript code to send posts on client clicks
  3. Fake PageModel to handle posts.

I don't really like this approach and I think it is too complex for such a simple task. This is my first APS.NET core Razor Pages project so I don't have much experience on how to implement such isolated components and hope you guys could guide me on how this could be implemented in a better way to follow SOLID and DRY principles.

Thanks.

Jeremy Caney
  • 7,102
  • 69
  • 48
  • 77
Aleksey
  • 51
  • 3

1 Answers1

0

You could have two ViewComponents:One is CommentsViewComponent which shows the list of previous comments and you could Edit/Delete a comment.Another is PostCommentViewComponent which you could add new a comment.For example:

@await Component.InvokeAsync("Comments")
@await Component.InvokeAsync("PostComment")

First of all, you could add Create/Edit/Delete razor pages in Pages/Comments folder with corresponding handler.

Then,in PostCommentViewComponent, you could use form submit to OnPostCreateAsync handler and redirect back.

public async Task<IViewComponentResult> InvokeAsync()
    {
        var comment = new Comment();
        return View(comment);
    }


//Default.cshtml

@model Razor.Models.Comment
<div class="row">
<div class="col-md-4">
    <form asp-page="./Comments/Create" asp-page-handler="Create">
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <div class="form-group">
            <label asp-for="Content" class="control-label"></label>
            <input asp-for="Content" class="form-control" />
            <span asp-validation-for="Content" class="text-danger"></span>
        </div>
        <div class="form-group">
            <input type="submit" value="Create" class="btn btn-default" />
        </div>
    </form>
</div>

//handler
public async Task<IActionResult> OnPostCreateAsync()
    {
        //create code

        await _context.SaveChangesAsync();

        return Redirect(Request.Headers["Referer"].ToString());
    }

In CommentsViewComponent, show all comments and enable user to redirect to razor pages to do editing/deleting and redirect back.

@model IEnumerable<Razor.Models.Comment>
<h4> Comment List</h4>
<table class="table">
<thead>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Content)
        </th>

        <th></th>
    </tr>
</thead>
<tbody>
    @foreach (var item in Model)
    {
        <tr>
            <td>

                @Html.DisplayFor(modelItem => item.Content)
            </td>             
            <td>
                <a asp-page="./Comments/Edit" asp-route-id="@item.CommentId">Edit</a> |
                <a asp-page="./Comments/Delete" asp-route- 
 id="@item.CommentId">Delete</a>
            </td>             
        </tr>          
    }
</tbody>

Ryan
  • 19,118
  • 10
  • 37
  • 53
  • Thanks for reply, I think that redirecting user to other pages for edit/delete comment is not good ui practice. It would be better to do this on the same page. For Delete we could just use confirm javascript and then send ajax post to Comments/Delete. As for Edit - i think better expirience would be also to use the same page. Usually on forums when you click Edit you see your message in textarea and when you click save your message get updated. I am not sure how to achieve that behaviour with Razor Pager rather then using javascript. – Aleksey Oct 18 '18 at 08:56
  • Anyway, if I understood your answer correctly, you also think that having dedicated Comments Razor Page with Post handlers is how-to approach to implement such component. Well, i would really prefer to somehow handle posts in ViewComponents which would allow to isolate all component code but i understand why it is not possible right now. – Aleksey Oct 18 '18 at 09:00
  • @Aleksy I think Razor Pages could not achieve that.If you want to edit in the same page, you may use SPA. – Ryan Oct 18 '18 at 10:05
  • using javascript you can achieve anything :). I am just trying to figure out the best approach. – Aleksey Oct 18 '18 at 11:13
  • Did you ever figure out the best way to do this? Any changes to razor pages and view components that make this easier? – Bitco Software Oct 20 '20 at 06:10