Is it possible to call ViewComponent from custom TagHelper?
Asked Answered
P

2

8

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?

Playwriting answered 4/7, 2017 at 19:57 Comment(0)
P
11

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>
Playwriting answered 4/7, 2017 at 19:57 Comment(2)
Thank you for this helpful answer. I just tried it and self-closing tag worked for me. But what does Contextualize() actually do?Exhaust
@Exhaust cool, they probably fixed that in later versions of a framework. Contextualize does something to make it work, haha. It was a long time ago and I guess I've tried different random things I saw people doing around the internets and that particular thing work. You can always look into framework's source code if you are thaaaat curious! ;)Playwriting
D
4

A follow up on the answer.

There is no need to write end tag when calling the tag helper. Just set the TagMode in ProcessAsync:

output.TagMode = TagMode.StartTagAndEndTag;
output.Content.SetHtmlContent(content);

Then <widget name="abc" /> works perfectly fine.

Alternatively, you can render the content of the view component in place of the widget tag without rendering the tag itself:

output.SuppressOutput();
output.PostElement.SetHtmlContent(content);

I also noticed that adding self-closing tags in the view component's view makes them appear wrong in the final result, but that may be a different topic.

Dunnite answered 30/4, 2018 at 16:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.