ASP.NET Core Razor Pages アプリで Html Helper の EditorFor や Tag Helper の input などを使用すると、ASP.NET がそれらから html の input 要素を生成する際、自動的に id 属性と name 属性を生成して id="id 名" name="name 名;" というように input 要素に追加します。その「id 名」や「name 名」をサーバー側で取得する方法を書きます。

先の記事「Control.ClientID と Html.IdFor」で書いた .NET Framework 版の MVC アプリとほぼ同じ話ですが、.NET 10 の ASP.NET Core Razor Pages で改めて調べてみましたので、それをこの記事に書いておくことにしました。
JavaScript を使ってそれらの要素を操作する場合 (例えばイベントにリスナーをアタッチするとか)、getElementById("id 名") を使って「id 名」に一致する html 要素を取得するということが行われます。
ASP.NET が生成する「id 名」をサーバー側で取得するには Html Helper の IdFor メソッドを利用します。「name 名」を取得する場合は NameFor メソッドが利用できます。
この記事の上の画像に id: Parent_Children_0__Name, name: Parent.Children[0].Name というように表示されていますが、それがその直上の input 要素(テキストボックス)に ASP.NET が追加した id 属性と name 属性の値です。
上の画像を表示した Razor Pages アプリのコードは以下の通りです。
Model
using System.ComponentModel.DataAnnotations;
namespace RazorPages.Models
{
public class Parent
{
public int Id { get; set; }
[Required(ErrorMessage = "{0} is required")]
[StringLength(5, ErrorMessage = "{0} must be within {1} characters")]
[Display(Name = "Parent Name")]
public string? Name { get; set; }
public IList<Child>? Children { get; set; }
}
public class Child
{
public int Id { get; set; }
[Required(ErrorMessage = "{0} is required")]
[StringLength(5, ErrorMessage = "{0} must be within {1} characters")]
[Display(Name = "Child Name")]
public string? Name { get; set; }
public Parent? Parent { get; set; }
}
}
.cshtml.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPages.Models;
namespace RazorPages.Pages
{
public class IdForModel : PageModel
{
public void OnGet()
{
var model = new Parent
{
Id = 1,
Name = "Parent1",
Children = new List<Child>
{
new Child { Id = 1, Name = "Child1" },
new Child { Id = 2, Name = "Child2" }
}
};
Parent = model;
}
[BindProperty]
public Parent? Parent { get; set; }
}
.cshtml
@page
@model RazorPages.Pages.IdForModel
<h3>Html Helper</h3>
@using (Html.BeginForm())
{
@Html.LabelFor(m => m.Parent!.Name)
@Html.EditorFor(m => m.Parent!.Name)
@Html.ValidationMessageFor(m => m.Parent!.Name)
<br />
for (int i = 0; i < Model.Parent!.Children!.Count; i++)
{
@Html.LabelFor(m => m.Parent!.Children![i].Name)
@Html.EditorFor(m => m.Parent!.Children![i].Name)
@Html.ValidationMessageFor(m => m.Parent!.Children![i].Name)
<br />
<span>
id: @Html.IdFor(m => m.Parent!.Children![i].Name),
name: @Html.NameFor(m => m.Parent!.Children![i].Name)
</span>
<br />
}
}
<br />
<h3>Tag Helper</h3>
<form method="post">
<label asp-for="Parent.Name"></label>
<input asp-for="Parent.Name"/>
<span asp-validation-for="Parent.Name"></span>
<br />
@for (int i = 0; i < Model.Parent!.Children!.Count; i++)
{
<label asp-for="Parent!.Children![i].Name"></label>
<input asp-for="Parent!.Children![i].Name" />
<span asp-validation-for="Parent!.Children![i].Name"></span>
<br />
<span>
id: @Html.IdFor(m => m.Parent!.Children![i].Name),
name: @Html.NameFor(m => m.Parent!.Children![i].Name)
</span>
<br />
}
</form>
例えば、上の Tag Helper のコード
<label asp-for="Parent!.Children![i].Name"></label>
<input asp-for="Parent!.Children![i].Name" />
<span asp-validation-for="Parent!.Children![i].Name"></span>
から ASP.NET が生成する html ソースは、i が 0 の場合、以下のようになります。Html Helper の場合もほぼ同じです。
<label for="Parent_Children_0__Name">Child Name</label>
<input type="text" data-val="true"
data-val-length="Child Name must be within 5 characters"
data-val-length-max="5"
data-val-required="Child Name is required"
id="Parent_Children_0__Name"
maxlength="5"
name="Parent.Children[0].Name"
value="Child1" />
<span class="field-validation-valid"
data-valmsg-for="Parent.Children[0].Name"
data-valmsg-replace="true"></span>
ASP.NET が自動的に生成して input 要素に追加する id 属性や name 属性の値はかなり複雑になるのが分かりますでしょうか? コレクションを扱うということで複雑になる例ではありますが、こういうケースは実際にあります。
html ソースを見れば ASP.NET が作成した「id 名」や「name 名」は分かりますが、それをスクリプトにハードコーディングするというのは避けた方が良さそうです。命名規則が変るかもしれないとか、ASP.NET Web Forms アプリのように使う場所によって変わるということがあるかもしれませんので。
ではどうするかというと、例えば、上の input 要素を JavaScript の getElementById で取得したい場合は、.cshtml ページ内でインラインスクリプトを書く場合ですが、以下のようにして取得できます。
@section scripts {
<script>
let element = document.getElementById('@Html.IdFor(m => m.Parent!.Children![0].Name)');
console.log(element.value);
// 結果は Child1
</script>
}
以上は ASP.NET Core Razor Pages の場合です。MVC の場合も同じだと思いますが、未確認・未検証です。