0
votes

My project uses .net core 2.0 MVC and I'm working with razor but I need some help.

I'm trying to replace this code:

<div class="form-group">
    <label asp-for="Address" class="control-label"></label>
    <input asp-for="Address" class="form-control" />
    <span asp-validation-for="Address" class="text-danger"></span>
</div>

by a tag helper that lets me write something like:

<add-edit-form-group ##Address##></add-edit-form-group>

I already have made folder TagHelpers add a file, and with this code it almost works, of course I need some help with passing arguments to the tag helper and then work on remove string and add the code.

The helper code is:

using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.TagHelpers;
using WebApp.Models;

namespace WebApp.TagHelpers
{
    public class AddEditFormGroupTagHelper : TagHelper
    {

        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            StringBuilder html = new StringBuilder();

            html.Append("<div class=\"form-group\">");
            html.Append("<label asp-for=\"Address\" class=\"control-label\"></label>");
            html.Append("<input asp-for=\"Address\" class=\"form-control\" />");
            html.Append("<span asp-validation-for=\"Address\" class=\"text-danger\"></span>");
            html.Append("</div>");

            output.Content.SetHtmlContent(html.ToString());
        }
    }
}
2

2 Answers

1
votes

It's not quite so simple. I would suggest studying the source for some of the existing tag helpers like InputTagHelper. There's a property on the like:

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

This is what captures the property to bind the input to.

Additionally, you will need an IHtmlGenerator which should be injected into the tag helper:

protected IHtmlGenerator generator;

public MyAwesomeTagHelper(IHtmlGenerator generator)
{
    this.generator = generator;
}

To actually use this, you'll also need a copy of the ViewContext, which can be property injected:

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

With all that in place, you can do stuff like the following to generate the code for your input, label, etc.

 var input = generator.GenerateTextBox(ViewContext, For.ModelExplorer, For.Name, For.Model, For.Metadata.EditFormatString, null);

However, using IHtmlGenerator is not for the light-hearted. It's pretty low-level. Also, you have to generate exactly what you need. For example, in the above, you're going to end up with an input with type="text" regardless of the type in play. If you've got a boolean and you need a checkbox instead, that's a totally different generator method you need to call. That means you have to do all the logic of determining what element gets generated for what type yourself, including taking into account things like DataTypeAttribute added to the property.

You can short-circuit some of this work by actually inheriting your tag helper from InputTagHelper, but that still won't help you with things like textareas, selects, etc.

Frankly, until or if Microsoft provides a way to render tag helpers from within other tag helpers (currently not possible), I'd say attempting to create a tag helper for this is going to be far more trouble and effort than it's worth. If you just want to reduce code duplication, you can still use editor templates as you could previously in MVC or just partial views, in general. If you go down the tag helper route, you're largely on your own.

0
votes

1.Before the class definition add [HtmlTargetElement("my-first-tag-helper")]

2.About the tag helper itself - add tag's name and mode:

output.TagName = "CustumTagHelper";  
output.TagMode = TagMode.StartTagAndEndTag;

3.Register the tag helper into _ViewImports.cshtml file:

@addTagHelper *, CustomTagHelper 

4.Now you can add it to the view:

<div class="row">  
    <my-first-tag-helper>  

    </my-first-tag-helper>  
</div>