Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to call ViewComponent from custom TagHelper?

I'm writing a custom TagHelper and want to render a ViewComponent inside it. Something similar to what vc:xyz tag helper does, but in a more controlled way, so that I can determine at runtime which ViewComponent to render.

Is it possible?

like image 867
IlliakaillI Avatar asked Jul 04 '17 19:07

IlliakaillI


People also ask

How do you call a ViewComponent from a controller?

View Components in Controller Methods Rather than passing the name of your view component, you can pass its Type object, giving you some IntelliSense support, as in this example: return ViewComponent(typeof(CustomerAddressViewComponent), new { CustomerId = "A123"});

How do I invoke a view component?

Invoke a view component directly from a controller View components are typically invoked from a view, but they can be invoked directly from a controller method. While view components don't define endpoints like controllers, a controller action that returns the content of a ViewComponentResult can be implemented.

What is the default path of view for ViewComponent?

View Components that inherit from ViewComponent class are able to call the View() method. When no specific view is called out, the view is searched in the following two ways and in the following order: Views/{ControllerName}/Components/{ComponentName}/Default. cshtml.

What is ViewComponent and can we inject dependency in ViewComponent?

A View Component class can be created in the following ways. Same as Controller class, View Component class must be non-abstract, public, and non-nested. This class fully supports constructor dependency injection. It does not take part in the Controller lifecycle so that we cannot use filters in the view component.


1 Answers

In order to do that, you need to inject IViewComponentHelper into your TagHelper, contextualize it and then use it to render any ViewComponent depending on your application logic. Here is a quick illustration:

[HtmlTargetElement("widget", Attributes = WidgetNameAttributeName)]
public class WidgetTagHelper : TagHelper
{
    private const string WidgetNameAttributeName = "name";
    private readonly IViewComponentHelper _viewComponentHelper;

    public WidgetTagHelper(IViewComponentHelper viewComponentHelper)
    {
        _viewComponentHelper = viewComponentHelper;
    }

    [HtmlAttributeNotBound]
    [ViewContext]
    public ViewContext ViewContext { get; set; }

    [HtmlAttributeName(WidgetNameAttributeName)]
    public string Name { get; set; }

    public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
    {
        ((IViewContextAware)_viewComponentHelper).Contextualize(ViewContext);

        var content = await _viewComponentHelper.InvokeAsync(typeof(WidgetViewComponent), new { name = Name });
        output.Content.SetHtmlContent(content);
    }
}

Also, keep in mind that self-closing tags will NOT work:

<widget name="abc" />

Use this form instead:

<widget name="abc"></widget>
like image 122
IlliakaillI Avatar answered Nov 15 '22 04:11

IlliakaillI