In ASP.NET Core, Html.Action has been replace by View Components.
In my opinion, View Components is very similar to Partial View in rendering them to the HTML. However, View Components executes the InvokeAsync
function before passing a model to the View. (We will talk about this later.)
Here are somethings that we should know about View Components,
- Not reachable directly as an HTTP endpoint, they are invoked from your code (usually in a view). A view component never handles a request.
- View component classes can be contained in any folder in the project.
- It can uses dependency injection.
InvokeAsync
exposes a method which can be called from a view, and it can take an arbitrary number of arguments.
(From ASP.NET Core Documents)
Let us take a look and learn how to use View Components.
Before we deep into View Components, create the controller and view as following.
[Area("Basic")]
[Route("Basic/[controller]/[action]")]
public class CustomerVcController : Controller
{
public IActionResult Index()
{
return View();
}
}
We will implement View later.
We could create the Default view in eitherViews\CustomerVc\Components\[View Component name]\Default.cshtml
orViews\Shared\Components\[View Component name]\Default.cshtml
The View Component will return the Default.cshtml
as View in default.
@model List<Angular2.Mvc.Core.Models.ViewModel.VmCustomer>
<div class="alert alert-info" role="alert">
@{
var title = "Hi, " + ViewBag.Description;
}
@title
</div>
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>
@Html.DisplayNameFor(model => model.First().Name)
</th>
<th>
@Html.DisplayNameFor(model => model.First().Age)
</th>
<th>
@Html.DisplayNameFor(model => model.First().Phone)
</th>
<th>
@Html.DisplayNameFor(model => model.First().Description)
</th>
<th></th>
</tr>
</thead>
<tbody>
@if (Model != null)
{
foreach (var item in Model)
{
<tr>
<td class="col-sm-2">
@(new Microsoft.AspNetCore.Html.HtmlString(item.Name))
</td>
<td class="col-sm-2">
@Html.DisplayFor(modelItem => item.Age)
</td>
<td class="col-sm-1">
@Html.DisplayFor(modelItem => item.Phone)
</td>
<td class="col-sm-2">
@Html.DisplayFor(modelItem => item.Description)
</td>
</tr>
}
}
</tbody>
</table>
Notice that ViewComponent
class can be put in any folder in the project.
I put it in the path just like controllers and views.
The ViewComponent should inherit ViewComponent
and implement InvokeAsync
function.
[ViewComponent(Name = "CustomerVc")]
public class CustomerViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(int? id, string name)
{
var items = await this.getCustomersAsync(id, name);
ViewBag.Description = "this view is from ViewComponent.";
return View(items); //Return Default.cshtml
}
private async Task<List<VmCustomer>> getCustomersAsync(int? id, string name)
{
//return something
}
}
The ViewComponent's name is "Customer" with the suffix “ViewComponent” of "CustomerViewComponent" being removed.
We can specify the ViewComponent name by the Attribute:
[ViewComponent(Name = "")]
Okay, we had implemented the ViewComponent, let us see how to use it in View or Controller.
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
@await Component.InvokeAsync("CustomerVc", new { name = "JB" })
</div>
Notice that View Components are still RENDERED ON SERVER SIDE, we will later use another way to render it in ajax way.
public IActionResult IndexVc()
{
return ViewComponent("CustomerVc", new { name = "JB" });
}
Before the ViewComponent returns a view, we invoke the InvokeAsync()
function.
So we could implement some logics inside the ViewComponent.
Here is a simple example, we will let ViewComponent return different view which depending on the parameter value.
First we should create another view for our ViewComponent.
And then update ViewComponent class.
public async Task<IViewComponentResult> InvokeAsync(string display, int? id, string name)
{
var items = await this.getCustomersAsync(id, name);
ViewBag.Description = "this view is from ViewComponent.";
if (!string.IsNullOrEmpty(display) && display.ToLower().Equals("card"))
return View("Card", items);
else
return View("Default", items);
}
@{
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div>
@await Component.InvokeAsync("CustomerVc", new {display="Card", name = "JB" })
</div>
We can create a Http method in Controller and just return the view (HTML) thru ViewComponent. (Just like returning PartialView!)
[HttpGet]
public IActionResult GetView([FromQuery] string name)
{
return ViewComponent("CustomerVc", new { name = "JB" });
}
<div id="ajaxCust"></div>
$(function () {
renderViewComponent();
function renderViewComponent() {
$("#ajaxCust").html("");
$.ajax({
dataType: "html",
url: getUri + "?name=Leia",
success: function (cust) {
$("#ajaxCust").append(cust);
}
})
}
})