ASP.NET Core MVCでタグヘルパーを選択します


162

ASP.NET Coreのselectタグヘルパーのヘルプが必要です。

選択タグヘルパーにバインドしようとしている従業員のリストがあります。私の従業員はaに属しており、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 asp-for="EmployeeId" asp-items="???" />

私はこれでいくつかの助けをいただければ幸いです。ありがとう。


3
追加する必要があると思ったものだけです
。select

ほんのヒント。足場コントローラーショーは、一般的にそのようなことを行うための最良の方法を示します
Neville Nazerane

回答:


379

選択タグヘルパーを使用したSELECT要素のレンダリング

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);
}

そして、作成ビューでSelectListEmployeeListプロパティから新しいオブジェクトを作成し、それを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);
}

また、ビューでは、のEmployeesプロパティを直接使用できますasp-items

@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>

クラスSelectListItemMicrosoft.AspNet.Mvc.Rendering名前空間に属しています。

select要素に明示的な終了タグを使用していることを確認してください。自己終了タグアプローチを使用する場合、タグヘルパーは空のSELECT要素をレンダリングします。

以下のアプローチは機能しません

<select asp-for="EmployeeId" asp-items="@Model.Employees" />

しかし、これはうまくいきます。

<select asp-for="EmployeeId" asp-items="@Model.Employees"></select>

エンティティフレームワークを使用してデータベーステーブルからデータを取得する

上記の例では、オプションにハードコードされたアイテムを使用しています。それで、多くの人々がそれを使用するので、私はエンティティフレームワークを使用してデータを取得するためにいくつかのサンプルコードを追加すると思いました。

さんがあなたのDbContextオブジェクトと呼ばれる性質があると仮定しましょうEmployeesタイプのものであり、エンティティ・クラスが持っていると、このような性質をDbSet<Employee>EmployeeIdName

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の使用

SelectListオプションのレンダリングに必要なアイテムを保持するためにクラスを使用することを好む人もいます。

public class MyViewModel
{
    public int EmployeeId { get; set; }
    public SelectList Employees { set; get; }
}

これでGETアクションで、SelectListコンストラクターを使用しEmployeesてビューモデルのプロパティを設定できます。パラメータdataValueFielddataTextFieldパラメータを指定していることを確認して ください。

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メソッドを呼び出して、それぞれIdFirstNameプロパティを持つEmployeeオブジェクトのリストを取得しています。作成したオブジェクトとしてDataValueField、それらのプロパティを使用DataTextFieldSelectListます。ハードコードされたリストを、データベーステーブルからデータを読み取るコードに変更できます。

ビューコードは同じになります。

<select asp-for="EmployeeId" asp-items="@Model.Employees" >
    <option>Please select one</option>
</select>

文字列のリストからSELECT要素をレンダリングします。

文字列のリストから選択要素をレンダリングしたい場合があります。その場合、あなたSelectListだけを取るコンストラクタを使用することができますIEnumerable<T>

var vm = new MyViewModel();
var items = new List<string> {"Monday", "Tuesday", "Wednesday"};
vm.Employees = new SelectList(items);
return View(vm);

ビューコードは同じになります。

選択したオプションの設定

SELECT要素のデフォルトオプションとして1つのオプションを設定したい場合があります(たとえば、編集画面で、以前に保存したオプション値をロードしたい場合)。これを行うには、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; }
}

これmultipleにより、ユーザーが複数のオプションを選択できる属性を持つselect要素のHTMLマークアップがレンダリングされます。

@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);
}

これにより、ページがレンダリングされるときに、複数選択要素でオプションのトムとジェリーが選択されます。

ViewBagを使用してアイテムのリストを転送する

オプションのリストをビューに渡すためにコレクションタイプのプロパティを保持したくない場合は、動的な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>

ViewBagを使用して項目のリストを転送し、選択したオプションを設定する

上記と同じです。必要なのは、プロパティ(ドロップダウンをバインドする対象)の値を、選択するオプションの値に設定することだけです。

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>

アイテムのグループ化

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アイテム内にオプションをレンダリングします。


1
ありがとうございました!SelectListへの変換を実行する必要がある古いかみそり構文のようなものです。再度、感謝します。
サム

7
空のオプションを追加する方法を探していました。使用していただきありがとう<option>Please select one</option>
ござい

5
終了</ select>タグが必要であることに注意してください-<select ... />のように選択タグを自己終了しようとしても機能しません。また、「1つ選択してください」などの空のオプションを使用する場合は、必須フィールドの検証を機能させるために、空の文字列「」の値を指定する必要があります。
アンディ

3
「select要素に明示的な終了タグを使用していることを確認してください。自己終了タグを使用する場合、タグヘルパーは空のSELECT要素をレンダリングします!」これは私の場合の問題でした。乾杯!
Mariusz

2
この回答にご尽力いただき、ありがとうございます。
Vidar

11

<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>");
            }
        }
    }
}

誤植はあるかもしれませんが、目的は明確だと思います。少し編集する必要がありました。


4

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;

4

以下の私の答えは質問を解決しませんが、関連していますしています。

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; }

かみそりのページではHtml.GetEnumSelectList<Counter>()、enumプロパティを取得するために使用できます。

<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>

3

複数の選択のために以下のコードを使用できます

<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>

0

Get:

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>
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.