2011-12-14 6 views
1

내 MVC3 면도기 양식이 서버에서 데이터를 올바르게 수신 했음에도 foreach 코드 블록 내에 중복 값을 렌더링한다는 것이 흥미 롭습니다.MVC3 면도기 "For"모델 - 내용이 복제 됨

[HttpPost] 
    public ActionResult Save(ViewModel.CategoryForm cat) 
    { 
     ... save the data based on posted "cat" values (I correctly receive them here) 

     List<Category> cL = ... populate category list here 
     return View(cL); 
    } 

수익률 위의 작업을 저장 - 내 .cshtml 페이지의 샘플

@model List<Category> 
@using (@Html.BeginForm("Save", "Categories", FormMethod.Post)) 
{ 
foreach (Category cat in Model) 
{ 
     <span>Test: @cat.CategoryName</span> 

     <span>Actual: @Html.TextBoxFor(model => cat.CategoryName)</span> 
     @Html.HiddenFor(model => cat.ID) 
     <p>---</p>    
} 

    <input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" /> 
} 

내 컨트롤러 액션이 같이 보입니다

- 여기 MVC3 면도기 내 간단한 양식 ...

이 이

입니다 정확한 데이터를 가진 모델.

위의 양식을 제출 후, 나는

Test: Category1, Actual:Category1 
Test: Category2, Actual:Category2 
Test: Category3, Actual:Category3 
Test: Category4, Actual:Category4 

그러나 @Html.TextBoxFor 목록에서 첫 번째 값을 복제 ...하여 작업 완료시 다음과 같은 카테고리의 값을 볼 것으로 예상. 양식을 게시 한 후 다음과 같은 응답이 표시됩니다. "실제"값은 서버에서 올바른 데이터를 얻더라도 반복됩니다.

Test: Category1, Actual:Category1 
Test: Category2, Actual:Category1 
Test: Category3, Actual:Category1 
Test: Category4, Actual:Category1 

내가 뭘 잘못하고 있니? 어떤 도움을 주시면 감사하겠습니다.

답변

3

TextBoxFor과 같은 도우미 메서드는 개체 컬렉션이 아닌 단일 개체를 나타내는 ViewModel과 함께 사용됩니다.

정상적인 사용은 다음과 같습니다 c이 방법 안에, 매핑됩니다

@Html.TextBoxFor(c => c.Name) 

, ViewData.Model에. 당신은 다른 일을하고있다

:

@Html.TextBoxFor(c => iterationItem.Name) 

메소드 internall 여전히 렌더링을위한 기본 개체로 ViewData.Model를 사용하려고합니다,하지만 당신은 반복 항목을 사용하려는. 이 구문은 컴파일러에서 유효하지만이 문제는 없습니다.

해결 방법은 단일 항목에 대해 작동하는 부분보기를 만드는 것입니다. 해당보기 내에서 올바른 구문 (첫 번째 예제)으로 html 헬퍼를 사용한 다음 반복 항목을 매개 변수로 전달하여 foreach 내부에서 호출 할 수 있습니다. 그건 제대로 작동합니다.

0

더 좋은 방법은 EditorTemplates를 사용하는 것입니다.

양식에서이 작업을 수행 할 것입니다 :

@model List<Category> 
@using (@Html.BeginForm("Save", "Categories", FormMethod.Post)) 
{ 
    @Html.EditorForModel() 
    <input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" /> 
} 

을 그런 다음 중 하나를 ~/조회/공유 폴더 또는 컨트롤러에보기, 당신이 원하는 여부에 따라 폴더를 (EditorTemplates라는 폴더를 만들 것 전체 응용 프로그램 또는 바로이 컨트롤러)와 템플릿을 공유하고, EditorTemplates 폴더에이처럼 보이는 Category.cshtml 파일을 만듭니다 :

@model Category 
<span>Test: @Model.CategoryName</span> 

<span>Actual: @Html.TextBoxFor(model => model.CategoryName)</span> 
@Html.HiddenFor(model => model.ID) 
<p>---</p>    

MVC는 자동으로 수집을 반복하고 대한 템플릿을 호출합니다 그 안에있는 각 항목.

0

뷰 내에서 foreach 루프를 사용하면 텍스트 상자의 이름 특성이 컬렉션의 모든 항목에 대해 동일하게 렌더링됩니다. 귀하의 예를 들어, 모든 텍스트 상자에 다음 ID로 렌더링되며 이름 속성 :

<input id="cat_CategoryName" name="cat.CategoryName" value="Category1" type="text"> 

컨트롤러가 양식 데이터 수집을 수신

, 서로 다른 값을 컬렉션을 재구성 할 수 없습니다.

내가 입양 한 좋은 패턴이 다시 게시 할 같은 클래스에보기를 결합하는 것입니다

  1. 솔루션. 이 예에서 모델은 List<Category>에 바인딩되지만 컨트롤러 Save 메서드는 모델 ViewModel.CategoryForm을받습니다. 나는 둘 다 똑같이 만들 것이다.

  2. foreach 대신 for 루프를 사용하십시오. name/id 속성은 고유 할 것이고 모델 바인더는 값을 구별 할 수 있습니다.

내 마지막 코드 :

보기

@model CategoryForm 
@using TestMvc3.Models 

@using (@Html.BeginForm("Save", "Categories", FormMethod.Post)) 
{ 
    for (int i = 0; i < Model.Categories.Count; i++) 
    { 
     <span>Test: @Model.Categories[i].CategoryName</span> 

     <span>Actual: @Html.TextBoxFor(model => Model.Categories[i].CategoryName)</span> 
     @Html.HiddenFor(model => Model.Categories[i].ID) 
     <p>---</p>    
    } 

    <input type="submit" value="Save" name="btnSaveCategory" id="btnSaveCategory" /> 
} 

컨트롤러

public ActionResult Index() 
{ 
    // create the view model with some test data 
    CategoryForm form = new CategoryForm() 
    { 
     Categories = new List<Category>() 
    }; 

    form.Categories.Add(new Category() { ID = 1, CategoryName = "Category1" }); 
    form.Categories.Add(new Category() { ID = 2, CategoryName = "Category2" }); 
    form.Categories.Add(new Category() { ID = 3, CategoryName = "Category3" }); 
    form.Categories.Add(new Category() { ID = 4, CategoryName = "Category4" }); 

    // pass the CategoryForm view model 
    return View(form); 
} 

[HttpPost] 
public ActionResult Save(CategoryForm cat) 
{ 
    // the view model will now have the correct categories 
    List<Category> cl = new List<Category>(cat.Categories); 

    return View("Index", cat); 
}