Author : MD TAREQ HASSAN
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:
- https://aspnetcore.readthedocs.io/en/stable/mvc/views/view-components.html
- https://docs.microsoft.com/en-us/aspnet/core/mvc/views/view-components
- https://medium.com/@jpdeffo/asp-net-core-razor-tag-helper-and-view-components-inside-a-container-3cb007001535
- https://www.cazton.com/blogs/technical/view-components-in-asp-net-core
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
- A view component class can be created by any of the following:
- Deriving from ViewComponent
- Decorating a class with the [ViewComponent] attribute, or deriving from a class with the [ViewComponent] attribute
- Creating a class where the name ends with the suffix ViewComponent
- Fully supports constructor dependency injection
- Doesn’t take part in the controller lifecycle, which means you can’t use filters in a view component
- All view component parameters are required
- Links:
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