Skip to content
This repository has been archived by the owner. It is now read-only.

Facility for rendering a partial template from a tag helper #5504

Closed
MissaouiChedy opened this issue Nov 5, 2016 · 2 comments
Closed

Facility for rendering a partial template from a tag helper #5504

MissaouiChedy opened this issue Nov 5, 2016 · 2 comments

Comments

@MissaouiChedy
Copy link

@MissaouiChedy MissaouiChedy commented Nov 5, 2016

Proposal

When creating a custom TagHelper it would be convenient to be able to render an existing partial view programatically and capture the rendered result in a string or an HtmlContent object inside the TagHelper.Process method.

For example, consider the following hypothetical custom TagHelper

`   
    public class CustomTagHelper : TemplateRenderingTagHelper
    {

        [HtmlAttributeName("asp-for")]
        public ModelExpression DataModel { get; set; }

        public override Task Process(TagHelperContext context, TagHelperOutput output)
        {
            output.TagName = "div";
            var renderedContent = HtmlHelper.Partial("~/Views/Shared/path/to/Template.cshtml");
            output.Content.SetHtmlContent(renderedContent);
        }
    }`

This tag helper inherits from the hypothetical TemplateRenderingTagHelper abstract class, this class would look like this:

`public abstract TemplateRenderingTagHelper : TagHelper
{
      protected IHtmlHelper HtmlHelper { get; set; }
      public TemplateRenderingTagHelper()
      {
            //Get a IHtmlHelper instance
            HtmlHelper = BuildAnIHtmlHelper();
      }
}
 `

As you can see this class makes available the HtmlHelper property for its sub classes, the HtmlHelper.Partial (or PartialAsync) can then be used to generate a template.

Motivation

Even if it is possible to call @Html.RenderPartial directly from the view, it is cleaner to factor the rendering inside the TagHelper.Process method especially if the rendering requires some preprocessing.
Consider the following TagHelper.Process example:

`
...
[HtmlAttributeName("asp-for")]
public ModelExpression DataModel { get; set; }
...
public override Task Process(TagHelperContext context, TagHelperOutput output)
{
      // Preprocessing on the model
      var model = SomeProcessingOn(DataModel.Model);
      // Building a Custom ViewData Dictionary
      var ViewData = BuildCustomViewDataDictWithCustomizedMetadata();
            
      output.TagName = "div";
      var renderedContent = HtmlHelper.Partial("~/Views/Shared/path/to/Template.cshtml", model, ViewData)
      output.Content.SetHtmlContent(renderedContent);
}`

@frankabbruzzese
Copy link

@frankabbruzzese frankabbruzzese commented Nov 6, 2016

@MissaouiChedy ,
Actually, you can use an HtmlHelper from within a TagHelper also now, with no need for further features:

  1. Add an IHtmlHelperargument to the constructor of your TagHelper, say: IHtmlHelper html, so that a fresh Html instance is injected when your TagHelper is created.
  2. Store it in a private variable, say html. The injected TagHlper is "neutral", not specific for your View, so you have to "contextualize" it for the current View Viecontext as explained in the steps below
  3. Add a property:
        [HtmlAttributeNotBound]
        [ViewContext]
        public ViewContext ViewContext { get; set; }

It will be automatically bound to your View ViewContext
4. In the TagHelper ProcessAsync method contextualize the HtmlHelper:

(html as IViewContextAware).Contextualize(ViewContext );

Done! Now you have a working HtmlHelper.

@MissaouiChedy
Copy link
Author

@MissaouiChedy MissaouiChedy commented Nov 6, 2016

@frankabbruzzese
Yes in fact it works.
I tried previously to get an IHtmlHelper by using dependency injection, but I got an exception whenever I called one of its methods.
It turned out that I missed the contextualization part.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants