2016-07-25 4 views
2

세션을 사용하여 유지되는 체크 상태를 가질 체크 박스 목록을 만들기위한 html 도우미를 작성하려고합니다. 대부분의 경우 작동하며 확인란을 선택하거나 선택을 취소하고 제출을 클릭하면 확인란 상태를 기억합니다. 그러나 확인란을 선택하고 제출 한 다음 체크 박스를 지우고 다시 제출하면 (모두 선택 취소 된 경우) 마지막 선택 사항을 기억하고 싶은 것 같습니다. 여기에 ... 내가 작성한 것입니다MVC에 확인란 목록을 유지하는 방법

[HomeController]

public ActionResult Index() 
{ 
    TestViewModel tvm = new TestViewModel(); 
    return View(tvm); 
} 

[HttpPost] 
public ActionResult Index(TestViewModel viewModel) 
{ 
    viewModel.SessionCommit(); 
    return View(viewModel); 
} 

[색인보기]

@model TestApp.Models.TestViewModel 

@{ 
    ViewBag.Title = "Index"; 
} 

@using (Html.BeginForm()) 
{ 
    <p>Checkboxes:</p> 
    @Html.CheckedListFor(x => x.SelectedItems, Model.CheckItems, Model.SelectedItems) 

    <input type="submit" name="Submit form" /> 
} 

[TestViewModel]

// Simulate the checklist data source 
public Dictionary<int, string> CheckItems 
{ 
    get 
    { 
     return new Dictionary<int, string>() 
     { 
      {1, "Item 1"}, 
      {2, "Item 2"}, 
      {3, "Item 3"}, 
      {4, "Item 4"} 
     }; 
    } 
} 

// Holds the checked list selections 
public int[] SelectedItems { get; set; } 


// Contructor 
public TestViewModel() 
{ 
    SelectedItems = GetSessionIntArray("seld", new int[0]); 
} 


// Save selections to session 
public void SessionCommit() 
{ 
    System.Web.HttpContext.Current.Session["seld"] = SelectedItems; 
} 


// Helper to get an int array from session 
int[] GetSessionIntArray(string sessionVar, int[] defaultValue) 
{ 
    if (System.Web.HttpContext.Current.Session == null || System.Web.HttpContext.Current.Session[sessionVar] == null) 
     return defaultValue; 

    return (int[])System.Web.HttpContext.Current.Session[sessionVar]; 
} 
, [HTML 헬퍼는]

public static MvcHtmlString CheckedList(this HtmlHelper htmlHelper, string PropertyName, Dictionary<int, string> ListItems, int[] SelectedItemArray) 
{ 
    StringBuilder result = new StringBuilder(); 
    foreach(var item in ListItems) 
    { 
     result.Append(@"<label>"); 
     var builder = new TagBuilder("input"); 
     builder.Attributes["type"] = "checkbox"; 
     builder.Attributes["name"] = PropertyName; 
     builder.Attributes["id"] = PropertyName; 
     builder.Attributes["value"] = item.Key.ToString(); 
     builder.Attributes["data-val"] = item.Key.ToString(); 
     if (SelectedItemArray.Contains(item.Key)) 
      builder.Attributes["checked"] = "checked"; 

     result.Append(builder.ToString(TagRenderMode.SelfClosing)); 
     result.AppendLine(string.Format(" {0}</label>", item.Value)); 
    } 
    return MvcHtmlString.Create(result.ToString()); 
} 
public static MvcHtmlString CheckedListFor<TModel, TProperty>(this HtmlHelper<TModel> htmlHelper, Expression<Func<TModel, TProperty>> expression, Dictionary<int, string> ListItems, int[] SelectedItemArray) 
{ 
    var name = ExpressionHelper.GetExpressionText(expression); 
    var metadata = ModelMetadata.FromLambdaExpression(expression, htmlHelper.ViewData); 
    return CheckedList(htmlHelper, name, ListItems, SelectedItemArray); 
} 

나는 this SO question을 읽은 나는 검사에는 체크 박스가 존재하지 않게되었을 때에,이 모델 바인더가 모르는와 함께 할 수있다 생각하지만, 나는 그 겪었어요하더라도 기타 다양한 게시물 - 나는 더 이상 앞으로 나아 가지 않습니다.

하나의 게시물에서 나는 숨겨진 필드가 확인란의 '거짓'상태를 전달하기 위해 확인란과 함께 사용되는 것을 보았지만 하나의 속성으로 여러 확인란을 사용하여 게시 할 수는 없었습니다. .

누구든지이 문제에 관해 밝힐 수 있습니까?

EDITED : demonstration project이 게시물에 강조 표시되어 있습니다. 바라기를 이것은 누군가 나를 도울 수 있습니다!

답변

3

모든 항목의 선택을 취소 할 때 주요 선택 사항과 이전 선택이 '기억'되는 이유는 모델에 마지막으로 저장 한 값을 저장하는 GetSessionIntArray()을 호출하는 생성자가 있다는 것입니다 형태. DefaultModelBinder은 먼저 기본 생성자를 호출하는 것을 포함하여 모델을 초기화 한 다음 양식 값을 기반으로 해당 속성의 값을 설정하여 작동합니다. 다음 시나리오

1 단계 : 그 첫 번째 전화를 가정하면 Index() 방법

  • 로 이동하는 아이템 Session에 등록되지 않은 다음 GetSessionIntArray() 의해 반환 SelectedItems의 값이되지 않는, int[0]이고 CheckItems의 모든 값과 일치하므로 확인란을 선택하지 않습니다.

2 단계 : 처음 2 개의 체크 박스를 확인하고 제출하십시오.

  • DefaultModelBinderTestViewModel의 새 인스턴스를 초기화하고 생성자를 호출합니다. SelectedItems의 값은 다시 int[0]입니다 (아직 Session에는 아무 것도 추가되지 않았습니다). 양식 값이 읽히고 SelectedItems의 값은 이제 int[1, 2] (선택란의 값)입니다.메서드 내부의 코드가 호출되고 int[1, 2]Session에 추가되어보기를 반환합니다.

3 단계 : 모든 체크 박스의 선택을 취소하고 다시 제출하십시오.

  • 귀하의 모델이 다시 초기화됩니다 만, 시간이 생성자는 Session의 값을 읽고 SelectedItems의 값이 int[1,2]입니다. DefaultModelBinderSelectedItems의 양식 값을 읽지 만 선택하지 않은 체크 박스는 값을 제출하지 않으므로 아무 것도 설정되지 않으며 SelectedItems의 값은 int[1,2]으로 유지됩니다. 그런 다음 뷰를 반환하고 도우미 당신은 null

    을 테스트하기 위해 확장 메서드의 코드를 모델에서 생성자를 제거하고 수정하여이 문제를 해결할 수 SelectedItems

의 값에 기초하여 상기 제 2 개의 체크 박스를 체크 귀하의 생성이 id attri 중복

if (SelectedItemArray != null && SelectedItemArray.Contains(item.Key)) 
{ 
    .... 

그러나

  1. 포함, 당신 구현에 다른 문제가 있습니다 각 체크 박스 (귀하의 builder.Attributes["id"] = PropertyName; 사용)에 대한 butes는 유효하지 않은 html입니다.

  2. builder.Attributes["data-val"] = item.Key.ToString();은 의미가 없습니다 (data-val="1", data-val="1" 등을 생성 함). 눈에 거슬리지 않는 클라이언트 측 유효성 검사를 위해 속성을 원할 경우, 속성은 data-val="true" data-val-required="The SelectedItems field is required."이됩니다. 그러나 당신은 즉, 인덱서 사용 (@Html.ValidationMessageFor()에 의해 생성 된 각각의 체크 박스의 name 속성은 구별되어야 할 필요가로 (오류 메시지에 대한 관련 자리 표시자를 필요가있을 것이다 -. name="[0].SelectedItems" 등)

  3. 당신의 속성 값을 사용하여 바인딩하지만 올바른 접근 방식 (모든 확장 방법 사용에 내장) 먼저 ViewDataDictionary 마지막으로 더 값이 발견되지 않으면, 다음 실제 모델 속성.

  4. 당신에서 다음 ModelState에서 값을 얻을 것입니다 마지막 매개 변수 (int[] SelectedItemArray)를 제거 할 수 있도록 var metadata = ModelMetadata..... 값을 사용하지 마십시오. 실제로는 expression 값을 반복하는 메서드입니다.

사이드 노트 : 귀하의 경우에는 숨겨진 필드를 사용할 수 없습니다. CheckboxFor() 메서드는 메서드가 bool 속성에 바인딩되기 때문에 추가 숨겨진 입력을 생성하며 값이 항상 제출되도록합니다.

내 권장 사항은 MvcCheckBoxList과 같은 패키지를 사용하는 것입니다 (적어도 내 자신의 확장 방법을 사용하지 않았으므로) 적어도 작성하는 방법을 더 잘 이해하기 위해 MVC 소스 코드를 공부할 때까지는 HtmlHelper 확장 방법 (사과 거슬리는 소리).

+0

위대한 반응과 거의 이해합니다. 답안에서 3과 4를 분명히 설명해 주시겠습니까? 나는 표현식을 사용하지 않는다는 것을 (4 절) 이해하지만 표현식의 값을 int 배열로 얻는 방법은 무엇입니까? 나는 당신의 추천을 듣지만, 나는 패키지/블랙 박스에 의존하는 대신에 이런 것들을 스스로하는 법을 배우고 싶다. 몇 달 전에 만 MVC를 시작 했으므로 여전히 MVC를 통해 작업하고 있습니다. – Simon

+0

항목 3 : 방법을 보려면 [private static MvcHtmlString InputHelper (...)] (https://aspnetwebstack.codeplex.com/SourceControl/latest#src/System.Web.Mvc/Html/InputExtensions.cs) 메서드를 참조하십시오. 도우미는 전형적으로'value' 속성과 검사 순서를 설정합니다. 'ModelState'가 먼저 체크 된 이유를 이해하려면 [이 답변]의 두 번째 부분 (http://stackoverflow.com/questions/26654862/textboxfor-displaying-initial-value-not-the-value-updated-from)을 참조하십시오. -code/26664111 # 26664111) –

+0

Item 4 :'ModelMetadata'의'Model' 속성은 모델을 포함하고 있습니다. 따라서'check CheckedList (htmlHelper, name, ListItems, metadata.Model);를 사용하고 마지막 매개 변수 –

관련 문제