ASP.NET Core MVC에서 태그 도우미 선택


162

ASP.NET Core의 select 태그 도우미에 대한 도움이 필요합니다.

선택 태그 도우미에 바인딩하려는 직원 목록이 있습니다. 내 직원은 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 태그를 닫으면 즉시 태그를 닫으십시오 </ select> 태그 도우미가 <select asp-for ...... />와 작동하지 않았습니다.
RoughPlace

그냥 팁. 비계 컨트롤러는 일반적으로 그러한 것들에 가장 좋은 방법을 보여줍니다
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);
}

작성보기 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);
}

그리고보기에서의 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>

엔티티 프레임 워크를 사용하여 데이터베이스 테이블에서 데이터 가져 오기

위의 예제는 옵션으로 하드 코딩 된 항목을 사용하고 있습니다. 그래서 많은 사람들이 그것을 사용하면서 Entity 프레임 워크를 사용하여 데이터를 가져 오는 샘플 코드를 추가 할 것이라고 생각했습니다.

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속성을 난으로 그 속성을 사용 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 요소에서 하나의 옵션을 기본 옵션으로 설정할 수 있습니다 (예 : 편집 화면에서 이전에 저장된 옵션 값을로드하려고 함). 그렇게하려면 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);
}

페이지가 렌더링 될 때 다중 선택 요소에서 Tom 및 Jerry 옵션이 선택됩니다.

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>

항목 그룹화

선택 태그 도우미 방법은 드롭 다운에서 그룹화 옵션을 지원합니다. 액션 메소드에서 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);
}

뷰 코드에는 변화가 없습니다. 선택 태그 헬퍼는 이제 2 개의 optgroup 항목 안에 옵션을 렌더링합니다 .


1
감사합니다! SelectList 로의 변환을 수행해야하는 오래된 면도기 구문과 비슷합니다. 다시 감사합니다.
Sam

7
빈 옵션을 추가하는 방법을 찾고있었습니다.<option>Please select one</option>
Serj Sagan

5
닫는 </ select> 태그가 있어야합니다. <select ... />와 같이 select 태그를 자체 닫으려고하면 작동하지 않습니다. 또한 "하나만 선택하십시오"와 같은 빈 옵션을 사용하는 경우 필수 필드 유효성 검사가 작동하려면 빈 문자열 ""의 값을 지정해야합니다.
Andy

3
"선택 요소에 명시적인 닫기 태그를 사용하고 있는지 확인하십시오. 자체 닫기 태그 접근 방식을 사용하면 태그 도우미가 빈 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>()에서 열거 형 속성을 가져 오는 데 사용할 수 있습니다 .

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