私は、ASP.NET Coreのselect tagヘルパーに関していくらか助けが必要です。
Select tag helperにバインドしようとしている従業員のリストがあります。私の従業員はList<Employee> EmployeesList
におり、選択された値はEmployeeId
プロパティに入ります。私のビューモデルは次のようになります。
public class MyViewModel
{
public int EmployeeId { get; set; }
public string Comments { get; set; }
public List<Employee> EmployeesList {get; set; }
}
私の従業員クラスは次のようになります。
public class Employee
{
public int Id { get; set; }
public string FullName { get; set; }
}
私の質問は、ドロップダウンリストにId
を表示しているときにどのように値としてFullName
を使用するように私のselect tagヘルパーに伝えるのですか?
<select asp-for="EmployeeId" asp-items="???" />
私はこれでいくらかの助けに感謝します。ありがとう。
GETアクションで、ビューモデルのオブジェクトを作成し、EmployeeList
コレクションプロパティを読み込み、それをビューに送信します。
public IActionResult Create()
{
var vm = new MyViewModel();
vm.EmployeesList = new List<Employee>
{
new Employee { Id = 1, FullName = "Shyju" },
new Employee { Id = 2, FullName = "Bryan" }
};
return View(vm);
}
そしてあなたのcreateビューで、SelectList
プロパティから新しいEmployeeList
オブジェクトを作成し、それをasp-items
プロパティの値として渡します。
@model MyViewModel
<form asp-controller="Home" asp-action="Create">
<select asp-for="EmployeeId"
asp-items="@(new SelectList(Model.EmployeesList,"Id","FullName"))">
<option>Please select one</option>
</select>
<input type="submit"/>
</form>
そして、送信されたフォームデータを受け入れるためのあなたのHttpPostアクションメソッド。
[HttpPost]
public IActionResult Create(MyViewModel model)
{
// check model.EmployeeId
// to do : Save and redirect
}
または
ビューモデルにドロップダウンアイテムのプロパティとしてList<SelectListItem>
がある場合。
public class MyViewModel
{
public int EmployeeId { get; set; }
public string Comments { get; set; }
public List<SelectListItem> Employees { set; get; }
}
そしてあなたの行動の中で、
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "1"},
new SelectListItem {Text = "Sean", Value = "2"}
};
return View(vm);
}
また、このビューでは、asp-items
にEmployees
プロパティを直接使用できます。
@model MyViewModel
<form asp-controller="Home" asp-action="Create">
<label>Comments</label>
<input type="text" asp-for="Comments"/>
<label>Lucky Employee</label>
<select asp-for="EmployeeId" asp-items="@Model.Employees" >
<option>Please select one</option>
</select>
<input type="submit"/>
</form>
クラスSelectListItem
はMicrosoft.AspNet.Mvc.Rendering
名前空間に属します。
Select要素に明示的な終了タグを使用していることを確認してください。自己終了タグアプローチを使用する場合、タグヘルパーは空のSELECT要素をレンダリングします。
以下のアプローチは機能しません
<select asp-for="EmployeeId" asp-items="@Model.Employees" />
しかしこれはうまくいくでしょう。
<select asp-for="EmployeeId" asp-items="@Model.Employees"></select>
上記の例では、オプションにハードコーディングされた項目を使用しています。だから私は多くの人がそれを使用するように私は私がエンティティフレームワークを使用してデータを取得するためにいくつかのサンプルコードを追加すると思いました。
DbContextオブジェクトがEmployees
というプロパティを持ち、Employee
エンティティクラスがId
およびName
プロパティを持つDbSet<Employee>
型であるとします。
public class Employee
{
public int Id { set; get; }
public string Name { set; get; }
}
LINQクエリを使用して従業員を取得し、LINQ式でSelectメソッドを使用して各従業員のSelectListItem
オブジェクトのリストを作成できます。
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = context.Employees
.Select(a => new SelectListItem() {
Value = a.Id.ToString(),
Text = a.Name
})
.ToList();
return View(vm);
}
context
があなたのdbコンテキストオブジェクトであると仮定します。ビューコードは上記と同じです。
オプションをレンダリングするのに必要なアイテムを保持するためにSelectList
クラスを使うことを好む人もいます。
public class MyViewModel
{
public int EmployeeId { get; set; }
public SelectList Employees { set; get; }
}
GETアクションでは、SelectList
コンストラクタを使用してビューモデルのEmployees
プロパティに値を設定できます。 dataValueField
およびdataTextField
パラメーターを指定していることを確認してください。
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = new SelectList(GetEmployees(),"Id","FirstName");
return View(vm);
}
public IEnumerable<Employee> GetEmployees()
{
// hard coded list for demo.
// You may replace with real data from database to create Employee objects
return new List<Employee>
{
new Employee { Id = 1, FirstName = "Shyju" },
new Employee { Id = 2, FirstName = "Bryan" }
};
}
ここではGetEmployees
メソッドを呼び出して、それぞれId
およびFirstName
プロパティを持つEmployeeオブジェクトのリストを取得し、それらのプロパティを作成したDataValueField
オブジェクトのDataTextField
およびSelectList
として使用します。ハードコードリストをデータベーステーブルからデータを読み取るコードに変更できます。
ビューコードは同じになります。
<select asp-for="EmployeeId" asp-items="@Model.Employees" >
<option>Please select one</option>
</select>
時には、文字列のリストからselect要素をレンダリングしたいかもしれません。その場合はIEnumerable<T>
だけを取るSelectList
コンストラクタを使うことができます。
var vm = new MyViewModel();
var items = new List<string> {"Monday", "Tuesday", "Wednesday"};
vm.Employees = new SelectList(items);
return View(vm);
ビューコードは同じになります。
場合によっては、1つのオプションをSELECT要素のデフォルトオプションとして設定する必要があります(たとえば、編集画面では、以前に保存したオプション値をロードします)。そのためには、EmployeeId
プロパティの値を、選択したいオプションの値に設定するだけです。
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "11"},
new SelectListItem {Text = "Tom", Value = "12"},
new SelectListItem {Text = "Jerry", Value = "13"}
};
vm.EmployeeId = 12; // Here you set the value
return View(vm);
}
これは、ページがレンダリングされるときにselect要素でTomというオプションを選択します。
複数選択ドロップダウンをレンダリングしたい場合は、ビューのasp-for
属性に使用するビューモデルプロパティを配列型に変更するだけです。
public class MyViewModel
{
public int[] EmployeeIds { get; set; }
public List<SelectListItem> Employees { set; get; }
}
これはselect要素のためのHTMLマークアップをmultiple
属性でレンダリングします。これはユーザーが複数のオプションを選択することを可能にします。
@model MyViewModel
<select id="EmployeeIds" multiple="multiple" name="EmployeeIds">
<option>Please select one</option>
<option value="1">Shyju</option>
<option value="2">Sean</option>
</select>
単一選択と同様に、EmployeeIds
プロパティ値を必要な値の配列に設定します。
public IActionResult Create()
{
var vm = new MyViewModel();
vm.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "11"},
new SelectListItem {Text = "Tom", Value = "12"},
new SelectListItem {Text = "Jerry", Value = "13"}
};
vm.EmployeeIds= new int[] { 12,13} ;
return View(vm);
}
ページがレンダリングされるとき、これはmulti select要素でオプションTomとJerryを選択します。
オプションのリストをビューに渡すためにコレクション型プロパティを保持したくない場合は、動的ViewBagを使用してそれを実行できます(これは、viewbagが動的であるため、私が個人的に推奨する方法ではありません。コードはキャッチされていないタイプミスエラーを起こしやすい)
public IActionResult Create()
{
ViewBag.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "1"},
new SelectListItem {Text = "Sean", Value = "2"}
};
return View(new MyViewModel());
}
そしてビューで
<select asp-for="EmployeeId" asp-items="@ViewBag.Employees">
<option>Please select one</option>
</select>
上記と同じです。あなたがしなければならないのは、あなたが選択したいオプションの値にプロパティ(あなたがドロップダウンをバインドしている)の値を設定することです。
public IActionResult Create()
{
ViewBag.Employees = new List<SelectListItem>
{
new SelectListItem {Text = "Shyju", Value = "1"},
new SelectListItem {Text = "Bryan", Value = "2"},
new SelectListItem {Text = "Sean", Value = "3"}
};
vm.EmployeeId = 2; // This will set Bryan as selected
return View(new MyViewModel());
}
そしてビューで
<select asp-for="EmployeeId" asp-items="@ViewBag.Employees">
<option>Please select one</option>
</select>
タグ選択ヘルパーメソッドは、ドロップダウンでのグループ化オプションをサポートします。あなたがしなければならないのは、あなたのアクションメソッドでそれぞれのGroup
のSelectListItem
プロパティ値を指定することです。
public IActionResult Create()
{
var vm = new MyViewModel();
var group1 = new SelectListGroup { Name = "Dev Team" };
var group2 = new SelectListGroup { Name = "QA Team" };
var employeeList = new List<SelectListItem>()
{
new SelectListItem() { Value = "1", Text = "Shyju", Group = group1 },
new SelectListItem() { Value = "2", Text = "Bryan", Group = group1 },
new SelectListItem() { Value = "3", Text = "Kevin", Group = group2 },
new SelectListItem() { Value = "4", Text = "Alex", Group = group2 }
};
vm.Employees = employeeList;
return View(vm);
}
ビューコードに変更はありません。 selectタグヘルパーは2つの optgroup 項目の中にオプションを表示するようになります。
このためにInterfaceと<options>
タグヘルパーを作成しました。そのため、IEnumerable<T>
コントロールを設定するたびにIEnumerable<SelectListItem>
項目を<select>
に変換する必要はありませんでした。
そしてそれは美しく機能すると思います...
使い方は次のようなものです。
<select asp-for="EmployeeId">
<option value="">Please select...</option>
<options asp-items="@Model.EmployeesList" />
</select>
タグヘルパーと連携させるには、そのインターフェイスをクラスに実装する必要があります。
public class Employee : IIntegerListItem
{
public int Id { get; set; }
public string FullName { get; set; }
public int Value { return Id; }
public string Text{ return FullName ; }
}
これらは必要なコードです:
インターフェース
public interface IIntegerListItem
{
int Value { get; }
string Text { get; }
}
<options>
タグヘルパー:
[HtmlTargetElement("options", Attributes = "asp-items")]
public class OptionsTagHelper : TagHelper
{
public OptionsTagHelper(IHtmlGenerator generator)
{
Generator = generator;
}
[HtmlAttributeNotBound]
public IHtmlGenerator Generator { get; set; }
[HtmlAttributeName("asp-items")]
public object Items { get; set; }
public override void Process(TagHelperContext context, TagHelperOutput output)
{
output.SuppressOutput();
// Is this <options /> element a child of a <select/> element the SelectTagHelper targeted?
object formDataEntry;
context.Items.TryGetValue(typeof(SelectTagHelper), out formDataEntry);
var selectedValues = formDataEntry as ICollection<string>;
var encodedValues = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
if (selectedValues != null && selectedValues.Count != 0)
{
foreach (var selectedValue in selectedValues)
{
encodedValues.Add(Generator.Encode(selectedValue));
}
}
IEnumerable<SelectListItem> items = null;
if (Items != null)
{
if (Items is IEnumerable)
{
var enumerable = Items as IEnumerable;
if (Items is IEnumerable<SelectListItem>)
items = Items as IEnumerable<SelectListItem>;
else if (Items is IEnumerable<IIntegerListItem>)
items = ((IEnumerable<IIntegerListItem>)Items).Select(x => new SelectListItem() { Selected = false, Value = ((IIntegerListItem)x).Value.ToString(), Text = ((IIntegerListItem)x).Text });
else
throw new InvalidOperationException(string.Format("The {2} was unable to provide metadata about '{1}' expression value '{3}' for <options>.",
"<options>",
"ForAttributeName",
nameof(IModelMetadataProvider),
"For.Name"));
}
else
{
throw new InvalidOperationException("Invalid items for <options>");
}
foreach (var item in items)
{
bool selected = (selectedValues != null && selectedValues.Contains(item.Value)) || encodedValues.Contains(item.Value);
var selectedAttr = selected ? "selected='selected'" : "";
if (item.Value != null)
output.Content.AppendHtml($"<option value='{item.Value}' {selectedAttr}>{item.Text}</option>");
else
output.Content.AppendHtml($"<option>{item.Text}</option>");
}
}
}
}
誤植があるかもしれませんが、その目的は明らかです。少し編集しなければなりませんでした。
IHtmlHelper.GetEnumSelectListを使用することもできます
// Summary:
// Returns a select list for the given TEnum.
//
// Type parameters:
// TEnum:
// Type to generate a select list for.
//
// Returns:
// An System.Collections.Generic.IEnumerable`1 containing the select list for the
// given TEnum.
//
// Exceptions:
// T:System.ArgumentException:
// Thrown if TEnum is not an System.Enum or if it has a System.FlagsAttribute.
IEnumerable<SelectListItem> GetEnumSelectList<TEnum>() where TEnum : struct;
以下のコードを複数選択に使用できます。
<select asp-for="EmployeeId" multiple="multiple" asp-items="@ViewBag.Employees">
<option>Please select</option>
</select>
あなたも使用することができます:
<select id="EmployeeId" name="EmployeeId" multiple="multiple" asp-items="@ViewBag.Employees">
<option>Please select</option>
</select>
取得中:
public IActionResult Create()
{
ViewData["Tags"] = new SelectList(_context.Tags, "Id", "Name");
return View();
}
投稿中:
var selectedIds= Request.Form["Tags"];
ビューで :
<label>Tags</label>
<select asp-for="Tags" id="Tags" name="Tags" class="form-control" asp-items="ViewBag.Tags" multiple></select>
以下の私の答えは問題を解決しませんしかしそれは関連にします。
次の例のように、誰かがクラスモデルの代わりにenum
を使っているとします。
public enum Counter
{
[Display(Name = "Number 1")]
No1 = 1,
[Display(Name = "Number 2")]
No2 = 2,
[Display(Name = "Number 3")]
No3 = 3
}
送信時に値を取得するためのプロパティ。
public int No { get; set; }
かみそりのページでは、enumプロパティを取得するためにHtml.GetEnumSelectList<Counter>()
を使うことができます。
<select asp-for="No" asp-items="@Html.GetEnumSelectList<Counter>()"></select>
次のHTMLが生成されます。
<select id="No" name="No">
<option value="1">Number 1</option>
<option value="2">Number 2</option>
<option value="3">Number 3</option>
</select>