2017年1月5日 星期四

[ASP.NET Core] View Components

 ASP.NET Core    View Components     MVC  


Introduction


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.



Let us take a look and learn how to use View Components.




Environment


Visual Studio 2015 Update 3
NPM: 3.10.3                                    
Microsoft.AspNetCore.Mvc 1.0.0



Implement


Create controller/view


Before we deep into View Components, create the controller and view as following.






CustomerVcController

[Area("Basic")]
[Route("Basic/[controller]/[action]")]
public class CustomerVcController : Controller
{
        public IActionResult Index()
        {
            return View();
        }
}

We will implement View later.


ViewComplonent : Default view

We could create the Default view in either
Views\CustomerVc\Components\[View Component name]\Default.cshtml

Or

Views\Shared\Components\[View Component name]\Default.cshtml

The View Component will return the Default.cshtml as View in default.





Default.cshtml

@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>


ViewComplonent : class

Notice that ViewComponent classe can be put in any folder in the project.
I put it in the path just like controllers and views.





CustomerViewComponent.cs

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
        }
}

PS.
The ViewComponent 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.

Use ViewComponent in View

index.cshtml

@{
    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.


OR use ViewComponent in Controller

public IActionResult IndexVc()
{
   return ViewComponent("CustomerVc", new { name = "JB" });
}


Result







ViewComplonent : Return different view

Before the ViewComponent return a view, we invoke the InvokeAsync() function.
So we could implement some logics inside the ViewComponent.
Here is a simple application, 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.

CustomerVcController.cs (Update)

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);
}



Index.cshtml (Update)

@{
    Layout = "~/Views/Shared/_Layout.cshtml";
}

<div>
    @await Component.InvokeAsync("CustomerVc", new {display="Card",  name = "JB" })
</div>



Result






Ajax rendering

We can create a Http method in Controller and just return the view (HTML) thru ViewComponent. (Just like returning PartialView!)

Controller

[HttpGet]
public IActionResult GetView([FromQuery] string name)
{
   return ViewComponent("CustomerVc", new { name = "JB" });
}


Index.cshtml

<div id="ajaxCust"></div>


javascript (jquery)


$(function () {
    renderViewComponent();

    function renderViewComponent() {
        $("#ajaxCust").html("");
        $.ajax({
            dataType: "html",
            url: getUri + "?name=Leia",
            success: function (cust) {
                $("#ajaxCust").append(cust);
            }
        })
    }
})



Result





Reference





沒有留言:

張貼留言