WebSurfer's Home

Filter by APML

コレクションのモデルバインディング

by WebSurfer 12. May 2026 18:33

ASP.NET Core MVC または Razor Pages アプリで、ユーザーがコレクションの要素の一部を削除して残りの要素を POST してきた場合に、送信されてきた残りの要素からなるコレクションのモデルバインディングを行うにはどうするかという話を書きます。

コレクションのモデルバインディング

先の記事「コレクションのデータアノテーション検証」に書きましたように、コレクションのモデルバインディングがうまく行われるようにするには、レンダリングされる input 要素の name 属性が連番のインデックスを含むようにします。具体的には、name="prefix[index].Property" というパターンとし、index は 0 から始まる連番とします。

この記事の例として上の画像のようなアプリを考えます。ユーザーが[Remove]ボタンをクリックしてある項目を削除してから[Submit]ボタンをクリックすると、残った項目のコレクションが POST されます。

その場合、POST されたコレクションの input 要素の name="prefix[index].Property" 属性の index が連続しなくなってしまいます。

index の数字の連続が途切れた場合、何も対応がされてなければそれ以降の要素はバインドされません。では、バインドされるようにするにはどういう対応を取ったらいいのでしょうか?

Microsoft のドキュメント「ASP.NET Core でのモデル バインド」の Collections のセクションの 5 つ目のコード例にある、selectedCourses.index=a&selectedCourses.index=b というような index を示すデータを一緒にPOST することにより連番でなくてもモデルバインドされるようになります。

例えば、index が 0 の場合、ASP.NET から以下の様な html 要素がレンダリングされるようにコーディングします。

<input type="hidden" name="prefix.Index" value="0" />
<input name="prefix[0].Property" value="ABC" />

参考に上の画像の ASP.NET Core Razor Pages アプリのコードを以下に載せてておきます。Visual Studio 2026 のテンプレートを使ってターゲットフレームワークを .NET 10 として作成したものです。

Model

using System.ComponentModel.DataAnnotations;

namespace RazorPages.Models
{    public class Country
    {
        [Required(ErrorMessage = "{0} は必須")]
        [StringLength(15, ErrorMessage = "{0} は {1} 文字以内")]
        [Display(Name = "国名")]
        public string Name { get; set; } = string.Empty;

        public CountryInfo Details { get; set; } = new();
    }

    public class CountryInfo
    {
        [Required(ErrorMessage = "{0} は必須")]
        [StringLength(15, ErrorMessage = "{0} は {1} 文字以内")]
        [Display(Name = "首都")]
        public string Capital { get; set; } = string.Empty;

        [Required(ErrorMessage = "{0} は必須")]
        [StringLength(15, ErrorMessage = "{0} は {1} 文字以内")]
        [Display(Name = "大陸")]
        public string Continent { get; set; } = string.Empty;
    }

    public class ListCountriesViewModel
    {
        public List<Country> CountryList { get; set; } = new();
        public List<Country> SelectedCountries { get; set; } = new();
    }
}

CountryList.cshtml.cs

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using RazorPages.Models;

namespace RazorPages.Pages
{
    public class CountryListModel : PageModel
    {
        [BindProperty]
        public ListCountriesViewModel List { get; set; } = new();

        public void OnGet()
        {
            List = new ListCountriesViewModel
            {
                CountryList = GetDefaultCountries()
            };
        }

        public IActionResult OnPost()
        {
            if (ModelState.IsValid)
            {
                var posted = List.CountryList;
                List = new ListCountriesViewModel
                {
                    CountryList = posted,
                    SelectedCountries = posted
                };

                // POST された値は ModelState ディクショナリ(model ではない)
                // に格納されていて、Tag Helper はまず ModelState ディクショ
                // ナリを調べ、そこに値があればそれを表示する仕組みになっている。
                // なので、posted の値の通り表示するには ModelState をクリア
                // する必要がある
                ModelState.Clear();                
            }
            else
            {
                List = new ListCountriesViewModel
                {
                    CountryList = GetDefaultCountries()
                };
            }

            return Page();
        }

        private static List<Country> GetDefaultCountries()
        {
            var countries = new List<Country>
            {
                new Country()
                {
                    Name = "Italy",
                    Details = new CountryInfo
                    {
                        Capital = "Rome",
                        Continent = "Europe"
                    }
                },
                new Country()
                {
                    Name = "Spain",
                    Details = new CountryInfo
                    {
                        Capital = "Madrid",
                        Continent = "Europe"
                    }
                },
                new Country()
                {
                    Name = "USA",
                    Details = new CountryInfo
                    {
                        Capital = "Washington",
                        Continent = "NorthAmerica"
                    }
                },
                new Country()
                {
                    Name = "Japan",
                    Details = new CountryInfo
                    {
                        Capital = "Tokyo",
                        Continent = "Asia"
                    }
                },
                new Country()
                {
                    Name = "Australia",
                    Details = new CountryInfo
                    {
                        Capital = "Canberra",
                        Continent = "Oceania"
                    }
                }
            };

            return countries;
        }
    }
}

CountryList.cshtml

@page
@model RazorPages.Pages.CountryListModel

<h4>Remove countries not to submit</h4>
<form method="post">
    <table class="table">
        <thead>
            <tr>
                <th>
                    <label asp-for="List.CountryList[0].Name"></label>
                </th>
                <th>
                    <label asp-for="List.CountryList[0].Details.Capital"></label>
                </th>
                <th>
                    <label asp-for="List.CountryList[0].Details.Continent"></label>
                </th>
                <th></th>
            </tr>
        </thead>
        <tbody>
            @for (int i = 0; i < Model.List.CountryList.Count; i++)
            {
                <tr class="country-row">
                    <input type="hidden" name="List.CountryList.Index" value="@i" />
                    <td>
                        <input asp-for="List.CountryList[i].Name" class="form-control" />
                        <span asp-validation-for="List.CountryList[i].Name" 
                            class="text-danger"></span>
                    </td>
                    <td>
                        <input asp-for="List.CountryList[i].Details.Capital" 
                            class="form-control" />
                        <span asp-validation-for="List.CountryList[i].Details.Capital" 
                            class="text-danger"></span>
                    </td>
                    <td>
                        <input asp-for="List.CountryList[i].Details.Continent" 
                            class="form-control" />
                        <span asp-validation-for="List.CountryList[i].Details.Continent" 
                            class="text-danger"></span>
                    </td>
                    <td>
                        <button type="button"
                                class="btn btn-danger"
                                onclick="this.closest('.country-row').remove();">
                            Remove
                        </button>
                    </td>
                </tr>
            }
        </tbody>
    </table>
    <input type="submit" value="Submit" class="btn btn-primary" />
</form>

<hr />
     
<h4>Countries submitted</h4>
<ul>
    @if (Model.List.SelectedCountries != null &&
         Model.List.SelectedCountries.Count > 0)
    {
        foreach (var country in Model.List.SelectedCountries)
        {
            <li>@country.Name</li>
        }
    }
    else
    {
        <li>No countries submitted.</li>
    }
</ul>

@section Scripts {
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }
}

Tags: , , ,

CORE

SQL Server のテーブルを Boorstrap Modal で編集・更新

by WebSurfer 25. March 2026 14:43

SQL Server のテーブルの CRUD を行う ASP.NET Core Razor Pages アプリで、ユーザーがレコードを編集・更新する際、対象レコードを Bootstrap Modal に表示し、ユーザーが編集を行った後 Bootstrap Modal 上の [Update] ボタンをクリックすると、レコードを更新する方法を紹介します。

Movie テーブルを Boorstrap Modal で編集・更新

先の記事「ASP.NET Core Razor Pages で Bootstrap Modal の利用」で Delete する前に削除するレコードの内容を確認するため Bootstrap Modal を使う方法を書きました。その続きです。

編集・更新は普通に別ページに遷移してそこで行って何ら不都合はないと思いますし、Bootstrap Modal を使うメリットはない(複雑になるデメリットしかない)とは思いますが、せっかく作ったのでブログに書いておくことにしました。

問題は Model のプロパティに付与する StringLength とか RegularExpression などのデータアノテーション属性によるユーザー入力の検証です。普通に別ページに遷移して行う時と同様、上の画像のように表示したいのですが、それがかなり面倒でした。特にクライアント側での検証を無効にしてサーバー側で検証を行う場合はいろいろ気を付けなければならないことがあります。

以下に、上の画像を表示するのに使った ASP.NET Core Razor Pages アプリのソースコードを載せて、気を付けるべき点を書いておきます。元になるアプリは、Visual Studio 2026 のテンプレートを使って、ターゲットフレームワーク .NET 10 で作成しました。

(1) Movie.cs(モデル)

ユーザー入力検証用のデータアノテーション属性をプロパティに付与します。この記事の例では Required、StringLength、Range を使いました。

using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace RazorPages.Models;

[Table("Movie")]
public partial class Movie
{
    [Key]
    public int Id { get; set; }

    [Display(Name = "タイトル")]
    [StringLength(128, MinimumLength = 5, 
        ErrorMessage = "{0}は{2}文字以上{1}文字以下でなければなりません。")]
    public string? Title { get; set; }

    [Display(Name = "公開日")]
    [Required(ErrorMessage = "{0}は必須です。")]
    [DisplayFormat(DataFormatString = "{0:yyyy年M月d日}")]
    public DateTime ReleaseDate { get; set; }

    [Display(Name = "ジャンル")]
    [StringLength(128, 
        ErrorMessage = "{0}は{1}文字以下でなければなりません。")]
    public string? Genre { get; set; }

    [Display(Name = "価格")]
    [Required(ErrorMessage = "{0}は必須です。")]
    [Range(100, 10000,
        ErrorMessage = "{0}は{1}から{2}の間でなければなりません。")]
    [DisplayFormat(DataFormatString = "{0:C0}")]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
}

(2) Movie2/Index.cshtml.cs

Visual Studio 2026 のスキャフォールディング機能を使って、SQL Server の Movie テーブルの CRUD を行うコードを自動生成させ、CRUD の Read を行う(レコード一覧を表示する)Index ページに手を加えました。

EditMovie プロパティ、OnGetMovieToEditAsync メソッド、OnPostUpdateAsync メソッド、MovieExists メソッドは、スキャフォールディング機能で自動生成された Movie2/Edit.cshtml.cs のコードに少し手を加えて使いました。コメントの説明を見てください。

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.EntityFrameworkCore;
using RazorPages.Models;
using RazorPages.Data;

namespace RazorPages.Pages.Movies2
{
    public class IndexModel : PageModel
    {
        private readonly TestDatabaseContext _context;

        public IndexModel(TestDatabaseContext context)
        {
            _context = context;
        }

        // 編集対象の Movie データの授受に用いるプロパティを追加
        [BindProperty]
        public Movie EditMovie { get; set; } = default!;

        public IList<Movie> Movie { get;set; } = default!;

        public async Task OnGetAsync()
        {
            Movie = await _context.Movies.ToListAsync();
        }

        // 指定された id のデータを Movie テーブルから取得し JSON 形式で返す
        // ハンドラを追加。このデータを Bootstrap Modal に表示する
        public async Task<IActionResult> OnGetMovieToEditAsync(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }

            var movie = await _context.Movies
                              .FirstOrDefaultAsync(m => m.Id == id);
            if (movie == null)
            {
                return NotFound();
            }
            
            return new JsonResult(movie);
        }

        // クライアントから送信されてきた EditMovie プロパティの内容でMovie
        // テーブルの当該レコードを更新するハンドラを追加
        public async Task<IActionResult> OnPostUpdateAsync()
        {
            if (!ModelState.IsValid)
            {
                // 検証エラーがある場合

                // Movie を再取得。これがないと return Page(); でリストを再表示す
                // る際、Index.cshtml の @foreach (var item in Model.Movie)
                // でエラーになる
                Movie = await _context.Movies.ToListAsync();

                // 検証エラーがあることを Index.cshtml に伝えるため、ViewData に
                // フラグをセット。これを受けて Index.cshtml ではモーダルを表示する
                ViewData["ValidationResult"] = "invalid";

                // 元の Index ページを再表示。上のフラグを "invalid" にセットして
                // いるので Index ページには Modal が表示され、EditMovie の内容
                // がエラーメッセージとともに表示される
                return Page();
            }

            _context.Attach(EditMovie).State = EntityState.Modified;

            try
            {
                await _context.SaveChangesAsync();
            }
            catch (DbUpdateConcurrencyException)
            {
                if (!MovieExists(EditMovie.Id))
                {
                    return NotFound();
                }
                else
                {
                    throw;
                }
            }

            return RedirectToPage("./Index");
        }

        private bool MovieExists(int id)
        {
            return _context.Movies.Any(e => e.Id == id);
        }
    }
}

(3) Movie2/Index.cshtml

リストの右横の Edit リンクをクリックすると JavaScript のメソッド openModal が呼び出され、その引数に当該レコードの id が渡されます。openModal は fetch を使ってハンドラ OnGetMovieToEditAsync を呼び出します。ハンドラ OnGetMovieToEditAsync は Movie テーブルから id で指定されたレコードを抽出し JSON 形式で返します。JSON を受け取ったらその内容を from タグ内の input 要素に書き込み、Modal を表示します。

ユーザーが Modal に表示された内容を編集後、[Update] ボタンをクリックすると、from タグには method="post" asp-page-handler="Update" と指定されているので、ハンドラ OnPostUpdateAsync に編集されたデータが post され、その内容で Movie テーブルの当該レコードが更新されます。

ポイントは from タグとその中身を、以下のコードのように、初期ページの内容に含むようにしておくことです。そうすることによって、サーバー側の検証 NG で元の Index ページに差し戻す際に、Modal 上のテキストボックスにはユーザーが編集した結果が表示され、検証 NG の場合はアノテーション属性に設定したエラーメッセージが表示されます。その結果がこの記事の上の画像です。

@page
@model RazorPages.Pages.Movies2.IndexModel

@{
    ViewData["Title"] = "Index";
}

<!-- Bootstrap Modal -->
<div class="modal fade" id="staticBackdrop" data-bs-backdrop="static"
     data-bs-keyboard="false" tabindex="-1"
     aria-labelledby="staticBackdropLabel" aria-hidden="true">
    <div class="modal-dialog">
        <div class="modal-content">
            <div class="modal-header">
                <h1 class="modal-title fs-5"
                    id="staticBackdropLabel">
                    Edit Movie
                </h1>
                <button type="button" class="btn-close"
                        data-bs-dismiss="modal" aria-label="Close"></button>
            </div>
            <div class="modal-body">
                <form method="post" asp-page-handler="Update">
                    <div asp-validation-summary="ModelOnly" class="text-danger"></div>
                    <input type="hidden" asp-for="EditMovie.Id" />
                    <div class="form-group">
                        <label asp-for="EditMovie.Title" class="control-label"></label>
                        <input asp-for="EditMovie.Title" class="form-control" />
                        <span asp-validation-for="EditMovie.Title" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <span class="text-danger">*</span>
                        <label asp-for="EditMovie.ReleaseDate" class="control-label"></label>
                        <input asp-for="EditMovie.ReleaseDate" class="form-control" aria-required="true" />
                        <span asp-validation-for="EditMovie.ReleaseDate" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <label asp-for="EditMovie.Genre" class="control-label"></label>
                        <input asp-for="EditMovie.Genre" class="form-control" />
                        <span asp-validation-for="EditMovie.Genre" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <span class="text-danger">*</span>
                        <label asp-for="EditMovie.Price" class="control-label"></label>
                        <input asp-for="EditMovie.Price" class="form-control" aria-required="true" />
                        <span asp-validation-for="EditMovie.Price" class="text-danger"></span>
                    </div>
                    <div class="form-group">
                        <input type="submit" value="Update" class="btn btn-primary" />
                    </div>
                </form>
            </div>
        </div>
    </div>
</div>

<h1>Index</h1>

<p>
    <a asp-page="Create">Create New</a>
</p>
<table class="table">
    <thead>
        <tr>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Title)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].ReleaseDate)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Genre)
            </th>
            <th>
                @Html.DisplayNameFor(model => model.Movie[0].Price)
            </th>
            <th></th>
        </tr>
    </thead>
    <tbody>
@foreach (var item in Model.Movie) {
        <tr>
            <td>
                @Html.DisplayFor(modelItem => item.Title)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.ReleaseDate)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genre)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Price)
            </td>
            <td>
                <a href="javascript:void(0);" 
                    onclick="openModal(@item.Id)">Edit</a>
            </td>
        </tr>
}
    </tbody>
</table>
@section scripts {
    @{
        await Html.RenderPartialAsync("_ValidationScriptsPartial");
    }

    <script>
        window.openModal = async function (id) {
            const url = '@Url.Page("/Movies2/Index", "MovieToEdit")' + '&id=' + id;
            const response = await fetch(url);
            if (response.ok) {
                const data = await response.json();
                document.getElementById('@Html.IdFor(model => model.EditMovie.Id)').value = data.id;
                document.getElementById('@Html.IdFor(model => model.EditMovie.Title)').value = data.title;
                document.getElementById('@Html.IdFor(model => model.EditMovie.ReleaseDate)').value = data.releaseDate;
                document.getElementById('@Html.IdFor(model => model.EditMovie.Genre)').value = data.genre;
                document.getElementById('@Html.IdFor(model => model.EditMovie.Price)').value = data.price;

                // クライアント側での検証を有効にしておくとユーザー入力不正で検証メッセージ
                // が表示される。ページを再描画しない限りその検証メッセージは書き換えられる
                // ことはないので、そこで Modal を閉じて別の行で Modal を再表示すると前回
                // の検証メッセージが残ってしまう。下のスクリプトで検証メッセージを消す
                const validators = document.querySelectorAll("span[data-valmsg-for]");
                validators.forEach(function (validator) {
                    validator.innerText = "";
                });

                // 上の fetch で取得したデータを Modal 内のテキストボックスにセットして
                // から Modal を表示する。下の 'staticBackdrop' は Modal の id です
                const modal = document.getElementById('staticBackdrop');
                const editModal = new bootstrap.Modal(modal);
                editModal.show();
            }
        };

        // クライアント側での検証を無効にしサーバー側で検証を行う場合に、検証結果が 
        // NG だった場合に Modal を再表示するためのスクリプト
        window.addEventListener('DOMContentLoaded', () => {
            if ('@ViewData["ValidationResult"]' === "invalid") {
                const modal = document.getElementById('staticBackdrop');
                const editModal = new bootstrap.Modal(modal);
                editModal.show();
            }
        });
    </script>
}

Tags: , , , , , ,

CORE

ASP.NET Core Razor Pages の IdFor と NameFor

by WebSurfer 13. March 2026 14:50

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

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 の場合も同じだと思いますが、未確認・未検証です。

Tags: , , ,

CORE

About this blog

2010年5月にこのブログを立ち上げました。主に ASP.NET Web アプリ関係の記事です。ブログ2はそれ以外の日々の出来事などのトピックスになっています。

Calendar

<<  July 2026  >>
MoTuWeThFrSaSu
293012345
6789101112
13141516171819
20212223242526
272829303112
3456789

View posts in large calendar