View components In-Depth in ASP.NET Core

ASP.Net Featured

View components is great feature in ASP.NET Core MVC. Let’s take an in-depth look at it in this article.

Table of Content

  • What is a view component
  • Where can a view component be used
  • How to create view component
  • How to use view component

What is ViewComponent?

From the definition in ASP.net website “View components are similar to partial views, but they are much more powerful. They don’t use model binding, and only depend on the data provided when calling onto it.”

They are special feature that is used to render data on a view file without actually being part of Http life cycle.

Where can this component be used in our application

View components can be used in place of partial views within our application where we have a reusable rendering with a complex logic. For example:

  • Dynamic navigation menu
  • Tree view
  • Dropdown List
  • Tag Cloud

Components of View Component

A view component consists of two parts :

app-parts

As you can see, c# class and .cshtml file are needed when creating view component.

View component file location

C# Class: Can be created anywhere in the solution. The best practice is to put all view component classes in one dedicated folder.

View file: The ASP.Net Core runtime searches for the view in the following paths:

  • /Views/{Controller Name}/Components/{View Component Name}/{View Name}
  • /Views/Shared/Components/{View Component Name}/{View Name}
  • /Pages/Shared/Components/{View Component Name}/{View Name}

The default view name for a view component is Default. So you need to name your view file ‘Default.cshtml’. This doesn’t mean that you can’t name your view anything you like but that’s the default.

Creating a view component

Create a new ASP.Net Core MVC web application. As we already know that we need two separate files for our view component namely the c# class and the html view.

The view component C# class

Create a folder named Components in the root of the web application, within this folder, create a class named TopCities. What we have just created is a c# class, there are few way in which this can be converted into a view component class:

  • 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

In our own case let’s decorate the class with viewcomponent attribute like so:

 [ViewComponent(Name ="CityComponent")]
 public class TopCities: ViewComponent
 {
 }

As the name suggest, we will be returning some list of cities into our view component. Let simulate some list of cities by creating a class within the models folder named city and paste the following:

public class City
    {
        public string country { get; set; }
        public string name { get; set; }
        public static List<City> ListCities()
        {
            return new List<City>(){
            new City{ country="NG",name="Lagos"},
            new City{ country="NG",name="Ikeja"},
            new City{ country="NG",name="Jos"},
            new City{ country="NG",name="Kaduna"},
            new City{ country="NG",name="Ibadan"},
            new City{ country="NG",name="Abuja"},
            new City{ country="NG",name="Port Harcourt"},
            };
        }
    }

The view component methods

A view component class can have several methods defined within it, however, there must be one method named InvokeAsync or Invoke, this a method that returns IViewComponentResult.

In TopCities class let modify the code to fetch list of cities.

    [ViewComponent(Name ="CityComponent")]
    public class TopCities: ViewComponent
    {       
        public async Task<IViewComponentResult> InvokeAsync()
        {
            var model = await Task.FromResult(cities());
            return View(model);
        }
        /// <summary>
        /// Fetch citie from database
        /// </summary>
        /// <returns></returns>
        List<City> cities()
        {
            return City.ListCities();
        }
    }

As you can see, we have two methods within the class – cities and InvokeAsync. In the invokeasync method we simply return the model without specifying the name of the view, this is because our view component will look for a view named Default.cshtml.

Creating the view component view

Create a folder named Component in the ~/Views/Shared folder and then create a folder within it with the name of our view component in this case ‘CityComponent’ and the create Default.cshtml file so the folder structure look like so:

view-component-project-structure-asp-net-core

Modify the Default.cshtml file

Let’s now modify the default.cshtml file to render a table containing the list of cities.

@model List<ViewComponentWeb.Models.City>
<table class="table table-striped" style="width:400px">
    <thead>
        <tr>
            <td>Country</td>
            <td>City</td>
        </tr>
    </thead>
    <tbody>
        @foreach (var city in Model)
        {
        <tr>
            <td>@city.country</td>
            <td>@city.name</td>
        </tr>
        }
    </tbody>
</table>

Invoking a view component

Invoking a view component means that we want to call it within the view where it is needed. To use the view component, just call the following inside the view:

@await Component.InvokeAsync("ViewComponentName", {Anonymous Type Containing Parameters})

You can aslo invoke view component as a Tag helper like so:

<vc:city-component diplay-format="dropdown">
</vc:city-component>

So in our index.cshtml in the ~/Views/Home folder let’s render our view component within it by adding this:

<div class="text-center">
    <h1 class="display-4">View Components</h1>
    
    @await Component.InvokeAsync("CityComponent")
</div>

As you can see, our view component does not take any parameter yet. Run the application and it should look exactly like this:

component-preview

Working with parameters in view component

To demonstrate how to accept parameters in view component, let say that we want to be able to display cities in different format like tables, and dropdowns. This will require us passing the viewFormat as a parameter and also have another .cshtml file for different view format.

In the ~/Views/Shared/Components/CityComponent folder, create a .cshtml file named DropDownView.cshtml and then add this markup that will make it return a dropdownlist:

@model List<ViewComponentWeb.Models.City>
<select class="form-control">
    @foreach (var city in Model)
    {
        <option value="@city.country">
            @city.name
        </option>
    }
</select>

Modify the view component method to take parameter

Now we need to modify the InvokeAsync method to take parameter and then decide on the view to render depending on the parameter values.

 public async Task<IViewComponentResult> InvokeAsync(string diplayFormat = "table")
        {
            var model = await Task.FromResult(cities());
            string viewName = string.Empty;
            switch (diplayFormat)
            {
                case "table":
                    viewName = "Default";
                    break;
                case "dropdown":
                    viewName = "DropDownView";
                    break;
                default:
                    break;
            }
            return View(viewName,model);
        }

As you can see now, we have two views and the view that get called now depend on the parameter passed. The diplayFormat parameter is an optional parameter that has “table” as the default value which means that if no parameter is passed, the method assume that we want to render a table. Let’s now render our view component side by side to see the effect. Modify the index.cshtml file like so:


<div class="text-center">
    <h1 class="display-4">View Components</h1>
    <div style="margin-top:50px" class="row">
        <div class="col-md-6">
            @await Component.InvokeAsync("CityComponent")
        </div>
        <div class="col-md-6">
            @await Component.InvokeAsync("CityComponent", new { diplayFormat = "dropdown" })
        </div>
    </div>
    
</div>

The first invoke method takes no parameter, while the second one take dropdown as an argument. Lets run the application and we get the following result.

app-preview-finished

That’s it. It is that simple to create and use view component in ASP.Net Core Applications. Hope this helps.

 

.

 

Similar Posts