カスタムタグヘルパーの色々な出力方法(ASP.NET CORE 6 MVC)

概要
カスタムタグヘルパーで色々なタグを出力します。
ここでは以下のものを説明します。
・ベースとなるタグヘルパーのサンプルを作る
・標準のInputタグを出力したい(ベースとなるタグヘルパーで説明)
・複数のタグを出力したい(ベースとなるタグヘルパーで説明)
・もとのタグを消したい
・もとのタグの前にタグを追加したい
・もとのタグの後にタグを追加したい
・もとのタグの中にタグを追加したい
・もとのタグとタグ内のコンテント(タグで囲まれた値、InnerHtml)の間にタグの階層を追加したい
・タグヘルパーにModelを渡したい(ベースとなるタグヘルパーで説明)
・タグヘルパーに配列を渡したい
・タグヘルパーにTypeを渡したい
ベースとなるタグヘルパー作り
まずはベースとなるタグヘルパーを作って、それを修正しながら色々な出力を行っていきます。
ついでにベースとなるタグヘルパーのなかで、IHtmlGeneratorを使った標準のInputタグ(TextBox)の出力と、複数のタグを出力する方法も説明します。
タグヘルパーのサンプルを動かすために必要になるのは以下のものになります。
※ControllerとView以外はパスはどこでも大丈夫です。
・タグヘルパー(Helpers/SampleTextTagHelper.cs)
・タグヘルパーを表示するためのサンプルView(Views/Test/Index.cshtml)
・サンプルViewで使うモデル(Models/Test/ViewModel/TestViewModel.cs)
・サンプルViewを表示するためのコントローラー(Controllers/TestController.cs)
タグヘルパー(Helpers/SampleTextTagHelper.cs)
「label」、「input(text)」、「input(hidden)」の3つのタグを出力するサンプルです。
labelとinput(text)はIHtmlGeneratorでASP.NET CORE標準のタグを出力しています。
IHtmlGeneratorは優秀で、ModelStateの考慮、Client Side Validationの考慮をしてくれます。
input(hidden)は、TagBuilderでタグを生成して出力しています。
詳細はコードのコメントを参照してください。
ポイントは以下になります。
- 「HtmlTargetElement」でタグヘルパークラスとHTML上のタグ名を紐づけます(HtmlTargetElementを指定しない場合はクラス名(からTagHelperを除いたもの)をケバブケース(xxx-xxx)に変換した名前がタグ名に使われる)。
- ViewContextはコンストラクターでDIするのではなく、プロパティに[ViewContext]属性を付与することでDIします。
- タグの属性の値はプロパティで受け取れます。デフォルトだとプロパティ名をケバブケースに変換したものが対応する属性名になります。明示的にプロパティに対する属性名を決めたい場合は「HtmlAttributeName」属性をプロパティに付与します。
- 処理に必要なクラスはコンストラクターでDIできます。
#nullable enable
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace TestWebCore3.Helpers
{
/// <summary>
/// サンプルテキストタグヘルパー
/// 通常のテキストタグを出力し
/// 同じ値でHiddenタグを出力する
/// テキストタグは「IHtmlGenerator」で生成しているため
/// ModelStateの考慮やClient Side Validationの考慮がされている
/// </summary>
/// <remarks>
/// HtmlTargetElementはカスタムタグヘルパーに紐づけるタグ名
/// HtmlTargetElementを付与しない場合はデフォルト値として
/// クラス名(からTagHelperをのぞいた)をケバブケースに変換したものが
/// タグ名として使われる
/// SampleTextTagHelperの場合はSampleTextの部分をケバブに変えたもの
/// sample-textがデフォルトのタグ名になる
/// 今はデフォルトと同じタグ名を明示的にHtmlTargetElementに指定している
/// </remarks>
[HtmlTargetElement("sample-text")]
public class SampleTextTagHelper : TagHelper
{
/// <summary>
/// コンテキスト
/// TagHelperの場合[ViewContext]属性をつけておくとDIしてくれる
/// [HtmlAttributeNotBound]は、タグの属性にview-contextというのがあった場合に
/// 本プロパティにバインドさせないようにするために付与する
/// </summary>
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext? ViewContext { get; set; }
/// <summary>
/// 慣例的にasp-for属性でタグに出力するモデルを受け取る
/// </summary>
[HtmlAttributeName("asp-for")]
public ModelExpression? For { get; set; }
/// <summary>
/// Html属性(dynamic objectで受け取る)
/// HtmlAttributeNameを指定しないとデフォルトの属性の名前は
/// ケバブ(html-attributes)になる
/// </summary>
public object? HtmlAttributes { get; set; }
/// <summary>
/// 一般的なタグヘルパーを出力するためのクラス
/// </summary>
private IHtmlGenerator _Generator;
/// <summary>
/// Model情報を取得するためのクラス
/// 実は今回のサンプルでは使わない。
/// </summary>
private IModelMetadataProvider _ModelMetadataProvider;
/// <summary>
/// Client Side Validation用のAttribute出力クラス
/// 初期段階では使わない
/// </summary>
private ValidationHtmlAttributeProvider _ValidationHtmlProvider;
/// <summary>
/// コンストラクター
/// </summary>
/// <param name="generator">標準のinputタグなどを出力するためのクラス</param>
/// <param name="modelMetadataProvider">Model情報を取得するためのクラス</param>
/// <param name="validationHtmlProvider">Client Side Validation用のクラス</param>
public SampleTextTagHelper(IHtmlGenerator generator
, IModelMetadataProvider modelMetadataProvider
, ValidationHtmlAttributeProvider validationHtmlProvider)
{
_Generator = generator;
_ModelMetadataProvider = modelMetadataProvider;
_ValidationHtmlProvider = validationHtmlProvider;
}
/// <summary>
/// タグ出力
/// </summary>
/// <param name="context">コンテキスト</param>
/// <param name="output">出力</param>
public override void Process(TagHelperContext context, TagHelperOutput output)
{
ArgumentNullException.ThrowIfNull(For, nameof(For));
ArgumentNullException.ThrowIfNull(HtmlAttributes, nameof(HtmlAttributes));
ArgumentNullException.ThrowIfNull(ViewContext, nameof(ViewContext));
// 普通のラベルタグを出力する
TagBuilder labelTag = _Generator.GenerateLabel(ViewContext
, For.ModelExplorer, For.Name, For.Metadata.DisplayName, null);
// 普通のinputタグを出力する
TagBuilder inputTag = _Generator.GenerateTextBox(ViewContext
, For.ModelExplorer, For.Name, For.Model, "", HtmlAttributes);
// もしくはタグを自分で生成して出力する
TagBuilder hiddenTag = new TagBuilder("input");
hiddenTag.MergeAttribute("type", "hidden");
hiddenTag.MergeAttribute("name", For.Name + "_hidden");
hiddenTag.MergeAttribute("value", For.Model?.ToString());
// タグを出力に追加する
output.Content.AppendHtml(labelTag);
output.Content.AppendHtml(inputTag);
output.Content.AppendHtml(hiddenTag);
}
}
}
サンプルViewで使用するモデル(Models/Test/ViewModel/TestViewModel.cs)
テストID、テスト番号という2つのstring型の項目をもつ、どこにでもある普通のモデルです。
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
namespace TestWebCore3.Models.Test.ViewModel
{
/// <summary>
/// テスト用のモデル
/// </summary>
public class TestViewModel
{
/// <summary>
/// テストID
/// </summary>
[DisplayName("テストID")]
[Required(AllowEmptyStrings = true, ErrorMessage = "{0}を入力してください")]
public string? TestId { get; set; }
/// <summary>
/// テスト番号
/// </summary>
[DisplayName("テスト番号")]
[Required(AllowEmptyStrings = true, ErrorMessage = "{0}を入力してください")]
[RegularExpression("^[0-9]+", ErrorMessage = "{0}は数字で入力してください")]
public string? TestNo { get; set; }
}
}
タグヘルパーを表示するためのサンプルView(Views/Test/Index.cshtml)
テストIDとテスト番号をSampleTextTagHelper(タグ名はsample-text)で出力します。
ポイントは以下のとおりです。
- addTagHelperでタグヘルパーが含まれるアセンブリ名を指定します。アセンブリ名はnamespaceではなく、ソースが格納されるDLL名(プロジェクト名)になります。
- jquery.validate.jsとjquery.validate.unobtrusive.jsはClient Side Validationを有効にするためのJavaScriptになります。
- タグのasp-for属性はSampleTextTagHelperのForプロパティにバインドされ、html-attributes属性はSampleTextTagHelperのHtmlAttributesプロパティにバインドされます。
- asp-forにはモデルのプロパティを指定しています(Model.TestId)。タグヘルパーのタグの属性の型がstring以外(ModelExpressionなど)の場合は””の中身はモデルのプロパティを指定したことになります。逆に属性がstring型の場合は固定文字列を指定したことになります。string型の属性に変数を格納したい場合、test-str = “@(Model.TestId)”など、@()で括って変数を展開します(test-strは例としてstring属性のプロパティ)。
@model TestWebCore3.Models.Test.ViewModel.TestViewModel
@* TagHelperを使用する際はAddTagHelperでTagHelperが格納されているAssembly名を指定する
Assembly名はnamespaceではなくプロジェクト名(DLLの名前)になる。
本プロジェクトの名前はTestWebCore3なのでTestWebCore3を指定している
*@
@addTagHelper *, TestWebCore3
@section scripts {
@* Jquery.jsは_Layout.cshtmlで読込み済の想定 *@
@* Client Side Validationを有効にするために下記2つのJSを読み込んでいる *@
<script src="~/lib/jquery-validation/dist/jquery.validate.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
}
<form asp-action="Check" asp-controller="Test">
@* エラーを出力する *@
@Html.ValidationSummary()
@*
カスタムタグヘルパー model.TestIdの値をバインドする
dynamic object型でhtmlタグの属性を渡す
*@
<sample-text asp-for="TestId" html-attributes="@(new {tabindex=1, style="width:80px;"})">
あいうえお
</sample-text>
@*
カスタムタグヘルパー model.TestNoの値をバインドする
dynamic object型でhtmlタグの属性を渡す
*@
<sample-text asp-for="TestNo" html-attributes="@(new {tabindex=2, style="width:100px;"})">
かきくけこ
</sample-text>
<input type="submit" value="クリック" class="btn btn-default" />
</form>
サンプルViewを表示するためのコントローラー(Controllers/TestController.cs)
何の変哲もないテスト用のコントローラーです。
画面初期表示用がIndexで、チェックボタンクリック時の処理がCheckになります。
using Microsoft.AspNetCore.Mvc;
using TestWebCore3.Models.Test.ViewModel;
namespace TestWebCore3.Controllers
{
/// <summary>
/// テスト用コントローラー
/// </summary>
public class TestController : Controller
{
/// <summary>
/// 初期表示
/// </summary>
/// <returns></returns>
public IActionResult Index()
{
TestViewModel model = new TestViewModel();
return View("Index",model);
}
/// <summary>
/// テスト用なのでなにもしない
/// </summary>
/// <param name="inputModel">本当はViewModelではなくInput用のModelを用意して受ける</param>
/// <returns></returns>
public IActionResult Check(TestViewModel model)
{
return View("Index", model);
}
}
}
実行結果(画面)

実行結果(HTML)
一部抜粋です。<sample-text>の子要素としてlabel、input(text)、input(hidden)が出力されています。
Client Side Validation用の属性が出力されているのがわかります。
<div b-h5jfl3y9ba="" class="container">
<main b-h5jfl3y9ba="" role="main" class="pb-3">
<form action="https://localhost:7257/Test/Check" method="post" novalidate="novalidate">
<div class="validation-summary-valid" data-valmsg-summary="true">
<ul><li style="display:none"></li></ul>
</div>
<sample-text>
<label for="TestId">テストID</label>
<input data-val="true" data-val-required="テストIDを入力してください" id="TestId" name="TestId" style="width:80px;" tabindex="1" type="text" value="">
<input name="TestId_hidden" type="hidden" value="">
</sample-text>
<sample-text>
<label for="TestNo">テスト番号</label>
<input data-val="true" data-val-regex="テスト番号は数字で入力してください" data-val-regex-pattern="^[0-9]+" data-val-required="テスト番号を入力してください" id="TestNo" name="TestNo" style="width:100px;" tabindex="2" type="text" value="">
<input name="TestNo_hidden" type="hidden" value="">
</sample-text>
<input type="submit" value="クリック" class="btn btn-default">
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NoLZtPk-fNLjKQV2jeAXtcCCzlx7Cht_P_wdHyCWzrpWVm5GmmGRqq0XbTPeiS29hmBwEHdgCpVzi9-ymlo5SOap7M2ehlNnvWAS0GfflrxcxTYI2D__s2fCHy_SQRp8MQYR8MZD6EBGGdw5hCfz7U">
</form>
</main>
</div>
<footer b-h5jfl3y9ba="" class="border-top footer text-muted">
<div b-h5jfl3y9ba="" class="container">
© 2023 - TestWebCore3 - <a href="https://localhost:7257/Home/Privacy">Privacy</a>
</div>
</footer>
<script src="./- TestWebCore3_files/jquery.min.js.ダウンロード"></script>
<script src="./- TestWebCore3_files/bootstrap.bundle.min.js.ダウンロード"></script>
<script src="./- TestWebCore3_files/site.js.ダウンロード"></script>
<script src="./- TestWebCore3_files/jquery.validate.js.ダウンロード"></script>
<script src="./- TestWebCore3_files/jquery.validate.unobtrusive.js.ダウンロード"></script>
もとのタグを消したい
やっと本題です。ベースとなるタグヘルパーでは<sample-text>タグの子要素としてinputタグが出力されましたが、<sample-text>の代わりにinputタグを出力したい場合の方法になります。
output.SuppressOutput()を実行します。
以下、SampleTextTagHelper.csのProcessメソッドの抜粋です。
// 自分自身のタグを消す
output.SuppressOutput();
// タグを出力に追加する
output.Content.AppendHtml(labelTag);
output.Content.AppendHtml(inputTag);
output.Content.AppendHtml(hiddenTag);
実行後のHTML(抜粋)
<sample-text>タグが出力されていないのがわかると思います。
<form action="/Test/Check" method="post" novalidate="novalidate">
<div class="validation-summary-valid" data-valmsg-summary="true">
<ul><li style="display:none"></li></ul>
</div>
<label for="TestId">テストID</label>
<input data-val="true" data-val-required="テストIDを入力してください" id="TestId" name="TestId" style="width:80px;" tabindex="1" type="text" value="">
<input name="TestId_hidden" type="hidden" value="">
<label for="TestNo">テスト番号</label>
<input data-val="true" data-val-regex="テスト番号は数字で入力してください" data-val-regex-pattern="^[0-9]+" data-val-required="テスト番号を入力してください" id="TestNo" name="TestNo" style="width:100px;" tabindex="2" type="text" value="">
<input name="TestNo_hidden" type="hidden" value="">
<input type="submit" value="クリック" class="btn btn-default">
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NoLZtPk-fNLjKQV2jeAXte2Nxreyu_XC_2dhz7LY6drNChHfS7t0_zHLDDs0m_NluGo8AXRKXnagOKr8T4GsG-kMLORLz-3pTfqE2OMA1nsRr5ENkaLp_odLs-H_jURL9qMSN1Hs_apD53Y1IM6uIs">
</form>
もとのタグの前・もとのタグの後にタグを追加したい
もとのタグの前にタグを追加したい場合はoutput.PreElement.AppendHtmlを使い、
もとのタグの後にタグを追加したい場合はoutput.PostElement.AppendHtmlを使います。
以下、SampleTextTagHelper.csのProcessメソッドの抜粋です。
// もとのタグの前にタグを追加する
output.PreElement.AppendHtml(labelTag);
// タグを出力に追加する
output.Content.AppendHtml(inputTag);
// もとのタグの後にタグを追加する
output.PostElement.AppendHtml(hiddenTag);
実行後のHTML(抜粋)
<form action="/Test/Check" method="post" novalidate="novalidate">
<div class="validation-summary-valid" data-valmsg-summary="true">
<ul><li style="display:none"></li></ul>
</div>
<label for="TestId">テストID</label>
<sample-text>
<input data-val="true" data-val-required="テストIDを入力してください" id="TestId" name="TestId" style="width:80px;" tabindex="1" type="text" value="">
</sample-text>
<input name="TestId_hidden" type="hidden" value="">
<label for="TestNo">テスト番号</label>
<sample-text>
<input data-val="true" data-val-regex="テスト番号は数字で入力してください" data-val-regex-pattern="^[0-9]+" data-val-required="テスト番号を入力してください" id="TestNo" name="TestNo" style="width:100px;" tabindex="2" type="text" value="">
</sample-text>
<input name="TestNo_hidden" type="hidden" value="">
<input type="submit" value="クリック" class="btn btn-default">
<input name="__RequestVerificationToken" type="hidden" value="CfDJ8NoLZtPk-fNLjKQV2jeAXtf45IYTqTED1kJI6oM1dMT9ovvbNt7D8JmacHI3NwYQK1_piX71NLzbvxeqNTnRjZyppfuPi_dHeVbuqc-jgTlP6cCb6XtmbjnQZClBw7O1DRJMFlLVciQPVA0MpxHI0i0">
</form>
もとのタグの中で、もとのコンテントの前後にタグを追加したい
output.PreContent.AppendHtmlやoutput.PostContent.AppendHtmlを使います。
// もとのタグの中で、コンテントの前にタグを追加する
output.PreContent.AppendHtml(labelTag);
output.PreContent.AppendHtml(inputTag);
// もとのタグの中で、コンテントの後にタグを追加する
output.PostContent.AppendHtml(hiddenTag);
もとのコンテント(あいうえお)を残した状態でタグが追加されているのがわかると思います(抜粋)。
<sample-text>
<label for="TestId">テストID</label>
<input data-val="true" data-val-required="テストIDを入力してください" id="TestId" name="TestId" style="width:80px;" tabindex="1" type="text" value="">
あいうえお
<input name="TestId_hidden" type="hidden" value="">
</sample-text>
<sample-text>
<label for="TestNo">テスト番号</label>
<input data-val="true" data-val-regex="テスト番号は数字で入力してください" data-val-regex-pattern="^[0-9]+" data-val-required="テスト番号を入力してください" id="TestNo" name="TestNo" style="width:100px;" tabindex="2" type="text" value="">
かきくけこ
<input name="TestNo_hidden" type="hidden" value="">
</sample-text>
もとのタグとコンテント(タグで囲まれた値、InnerHtml)の間にタグの階層を追加したい
output.GetChildContentAsync()でコンテント(例では「あいうえお」や「かきくけこ」)を取得後、TagBuilderでタグを作成し、そのタグにコンテントを設定して、作成したタグをoutput.Content.AppendHtmlで追加します。
なお、output.GetChildContentAsyncは非同期のため、ProcessもProcessAsyncに書き換えます。
/// <summary>
/// タグ出力
/// </summary>
/// <param name="context">コンテキスト</param>
/// <param name="output">出力</param>
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
ArgumentNullException.ThrowIfNull(For, nameof(For));
ArgumentNullException.ThrowIfNull(HtmlAttributes, nameof(HtmlAttributes));
ArgumentNullException.ThrowIfNull(ViewContext, nameof(ViewContext));
// 普通のラベルタグを出力する
TagBuilder labelTag = _Generator.GenerateLabel(ViewContext, For.ModelExplorer, For.Name, For.Metadata.DisplayName, null);
// 普通のinputタグを出力する
TagBuilder inputTag = _Generator.GenerateTextBox(ViewContext, For.ModelExplorer, For.Name, For.Model, "", HtmlAttributes);
// もしくはタグを自分で生成して出力する
TagBuilder hiddenTag = new TagBuilder("input");
hiddenTag.MergeAttribute("type", "hidden");
hiddenTag.MergeAttribute("name", For.Name + "_hidden");
hiddenTag.MergeAttribute("value", For.Model?.ToString());
// コンテントを取得する
TagHelperContent content = await output.GetChildContentAsync();
// 適当なタグ(ここではdiv)を作る
TagBuilder divTag = new TagBuilder("div");
// divタグにコンテントを設定する
divTag.InnerHtml.AppendHtml(content);
// divタグをもとのタグに追加する
output.Content.AppendHtml(divTag);
}
実行結果(抜粋)。<sample-text>とコンテント(あいうえお)の間に<div>の階層が挟まれているのがわかると思います。
<sample-text>
<div>
あいうえお
</div>
</sample-text>
<sample-text>
<div>
かきくけこ
</div>
</sample-text>
タグヘルパーに配列を渡したい
配列や変数をタグヘルパーの属性に指定する場合は@()で括って指定します。
まずはサンプルのタグヘルパーを以下のように修正します。
string[]? StrArray を追加しています。
なお、今回はAppendHtmlにタグではなく文字列を指定しています。
#nullable enable
using Microsoft.AspNetCore.Mvc.ModelBinding;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
namespace TestWebCore3.Helpers
{
/// <summary>
/// サンプルテキストタグヘルパー
/// 通常のテキストタグを出力し
/// 同じ値でHiddenタグを出力する
/// テキストタグは「IHtmlGenerator」で生成しているため
/// ModelStateの考慮やClient Side Validationの考慮がされている
/// </summary>
/// <remarks>
/// HtmlTargetElementはカスタムタグヘルパーに紐づけるタグ名
/// HtmlTargetElementを付与しない場合はデフォルト値として
/// クラス名(からTagHelperをのぞいた)をケバブケースに変換したものが
/// タグ名として使われる
/// SampleTextTagHelperの場合はSampleTextの部分をケバブに変えたもの
/// sample-textがデフォルトのタグ名になる
/// 今はデフォルトと同じタグ名を明示的にHtmlTargetElementに指定している
/// </remarks>
[HtmlTargetElement("sample-text")]
public class SampleTextTagHelper : TagHelper
{
/// <summary>
/// コンテキスト
/// TagHelperの場合[ViewContext]属性をつけておくとDIしてくれる
/// [HtmlAttributeNotBound]は、タグの属性にview-contextというのがあった場合に
/// 本プロパティにバインドさせないようにするために付与する
/// </summary>
[HtmlAttributeNotBound]
[ViewContext]
public ViewContext? ViewContext { get; set; }
/// <summary>
/// 慣例的にasp-for属性でタグに出力するモデルを受け取る
/// </summary>
[HtmlAttributeName("asp-for")]
public ModelExpression? For { get; set; }
/// <summary>
/// Html属性(dynamic objectで受け取る)
/// HtmlAttributeNameを指定しないとデフォルトの属性の名前は
/// ケバブ(html-attributes)になる
/// </summary>
public object? HtmlAttributes { get; set; }
/// <summary>
/// 配列受け取りのサンプル
/// </summary>
public string[]? StrArray { get; set; }
/// <summary>
/// 一般的なタグヘルパーを出力するためのクラス
/// </summary>
private IHtmlGenerator _Generator;
/// <summary>
/// Model情報を取得するためのクラス
/// 実は今回のサンプルでは使わない。
/// </summary>
private IModelMetadataProvider _ModelMetadataProvider;
/// <summary>
/// Client Side Validation用のAttribute出力クラス
/// 初期段階では使わない
/// </summary>
private ValidationHtmlAttributeProvider _ValidationHtmlProvider;
/// <summary>
/// コンストラクター
/// </summary>
/// <param name="generator">標準のinputタグなどを出力するためのクラス</param>
/// <param name="modelMetadataProvider">Model情報を取得するためのクラス</param>
/// <param name="validationHtmlProvider">Client Side Validation用のクラス</param>
public SampleTextTagHelper(IHtmlGenerator generator
, IModelMetadataProvider modelMetadataProvider
, ValidationHtmlAttributeProvider validationHtmlProvider)
{
_Generator = generator;
_ModelMetadataProvider = modelMetadataProvider;
_ValidationHtmlProvider = validationHtmlProvider;
}
/// <summary>
/// タグ出力
/// </summary>
/// <param name="context">コンテキスト</param>
/// <param name="output">出力</param>
public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output)
{
ArgumentNullException.ThrowIfNull(For, nameof(For));
ArgumentNullException.ThrowIfNull(HtmlAttributes, nameof(HtmlAttributes));
ArgumentNullException.ThrowIfNull(ViewContext, nameof(ViewContext));
// 普通のラベルタグを出力する
TagBuilder labelTag = _Generator.GenerateLabel(ViewContext, For.ModelExplorer, For.Name, For.Metadata.DisplayName, null);
// 普通のinputタグを出力する
TagBuilder inputTag = _Generator.GenerateTextBox(ViewContext, For.ModelExplorer, For.Name, For.Model, "", HtmlAttributes);
// もしくはタグを自分で生成して出力する
TagBuilder hiddenTag = new TagBuilder("input");
hiddenTag.MergeAttribute("type", "hidden");
hiddenTag.MergeAttribute("name", For.Name + "_hidden");
hiddenTag.MergeAttribute("value", For.Model?.ToString());
// コンテントを取得する
TagHelperContent content = await output.GetChildContentAsync();
string contentStr = content.GetContent();
// StrArrayを追加する
if (StrArray != null)
{
foreach (string data in StrArray)
{
output.Content.AppendHtml($"{contentStr} {data}<br>");
}
}
}
}
}
Viewは以下のようにして配列を渡します(抜粋)。
<sample-text asp-for="TestId" str-array="@(new string[]{"リンス","シャンプ"})" html-attributes="@(new {tabindex=1, style="width:80px;"})">
あいうえお
</sample-text>
HTMLの出力は以下のようになります(抜粋)。
<sample-text>
あいうえお リンス<br>
あいうえお シャンプ<br>
</sample-text>
<sample-text>
かきくけこ
</sample-text>