Author : HASSAN MD TAREQ

What is a View Component

  • A view component is a C# class that provides a partial view independently from the parent view and the action that renders it
  • A view component can be thought of as a specialized action, but one that is used only to provide a partial view with data; it cannot receive HTTP requests, and the content that it provides will always be included in the parent view
  • A view component:
    • Renders a chunk rather than a whole response
    • Includes the same separation-of-concerns and testability benefits found between a controller and view
    • Can have parameters and business logic
    • Is typically invoked from a layout page
  • View components don’t use model binding, and only depend on the data you provide when calling into it
  • View components have their own controllers (consider ViewComponent is standalone MVC in the way area can be considered Mini MVC)
  • View component allows to have full separation of concerns and makes view components much easier to unit test
  • Like controllers, view components must be public, non-nested, and non-abstract classes
  • A view component class:
    • Fully supports constructor dependency injection
    • Does not take part in the controller lifecycle, which means you can’t use filters in a view component
  • View component views must be placed in a folder named Components
  • If your view component needs to be used with many controllers, it should be placed in the Views\Shared\Components folder (otherwise, it can be placed as a subfolder under the Views folder for the target controller)
  • Links:

Resolving view component view

View component is resolved in the same way razor views are resolved for controller actions - by convention

  • ViewComponents/{Foo}ViewComponent.cs (‘ViewComponents’ folder is in project root folder, folder name can be anything, named ‘ViewComponents’ as good practice)
  • Views/Shared/Components/{Foo}/Default.cshtml (folder name ‘Components’ is mandatory since ViewComponent view will be resolved by convention)
  • Default.cshtml => Default is used for the view name by convention
  • To use view name other than ‘Default’ => https://aspnetcore.readthedocs.io/en/stable/mvc/views/view-components.html#specifying-a-view-name

Creating ViewComponent

ViewComponent class: ViewComponents/SpeakerCardViewComponent.cs

using Microsoft.AspNetCore.Mvc;
using WebAppTagHelper.Models;

namespace WebAppTagHelper.ViewComponents
{
    public class SpeakerCardViewComponent : ViewComponent
    {
        public IViewComponentResult Invoke(Speaker speaker)
        {
            return View(speaker);
        }
    }
}

ViewComponent view: Views/Home/Components/SpeakerCard/Default.cshtml

@model WebAppTagHelper.Models.Speaker


<div class="col-xs-12 col-sm-6 col-md-4 col-lg-3">
    <div class='card'>
        <div class='card-img'>
            <img src='static/speakers/Speaker-@(Model.SpeakerId).jpg' />
        </div>
        <h4 class='card-title'>
            <a href='#'>@(Model.UserFirstName) @(Model.UserLastName)</a>
        </h4>
        <p class='card-position'>@(Model.Company)</p>
        <p class='card-description'>Session time to be announced</p>
        <ul class='social'>
            <li>
                <a target='_blank' href='#'>LinkedIn</a>
            </li>
            <li>
                <a target='_blank' href='#'>Microsoft</a>
            </li>
        </ul>
    </div>
</div>

Invoking a view component

From view: Component.InvokeAsync(...)

<div class="container">
    <speaker-track track-name="JavaScript">
        @await Component.InvokeAsync("SpeakerCard", speakers[0])
        @await Component.InvokeAsync("SpeakerCard", speakers[1])
        @await Component.InvokeAsync("SpeakerCard", speakers[2])
    </speaker-track>
</div>

From view: tag helper syntax (must use prefix vc:)

<div class="container">
    <speaker-track track-name="JavaScript">
        <vc:speaker-card speaker=@speakers[0]></vc:speaker-card>
        <vc:speaker-card speaker=@speakers[1]></vc:speaker-card>
        <vc:speaker-card speaker=@speakers[2]></vc:speaker-card>
    </speaker-track>
</div>

From controller

public IActionResult IndexVC()
{
  return ViewComponent("PriorityList", new { maxPriority = 3, isDone = false });
}

Details: https://aspnetcore.readthedocs.io/en/stable/mvc/views/view-components.html#invoking-a-view-component