program tip

MVC 4 목록 모델 바인딩은 어떻게 작동합니까?

radiobox 2020. 12. 9. 08:02
반응형

MVC 4 목록 모델 바인딩은 어떻게 작동합니까?


양식의 입력 세트를 ListMVC 4에서 바인딩하려면 input name속성에 대한 다음 명명 규칙 이 작동 한다는 것을 알고 있습니다.

<input name="[0].Id" type="text" />
<input name="[1].Id" type="text" />
<input name="[2].Id" type="text" />

하지만 모델 바인더가 얼마나 용서하는지 궁금합니다. 예를 들어, 다음은 어떻습니까?

<input name="[0].Id" type="text" />
<input name="[3].Id" type="text" />
<input name="[8].Id" type="text" />

모델 바인더는 이것을 어떻게 처리합니까? List길이가 9 인 a 에 null을 바인딩 합니까? 아니면 여전히 List길이 3에 바인딩 됩니까? 아니면 완전히 질식할까요?

내가 신경 쓰는 이유

사용자가 양식에 행을 추가하고 양식에서 행을 삭제할 수있는 동적 양식을 구현하고 싶습니다. 따라서 사용자가 총 8 개 행 중 2 번째 행을 삭제하면 모든 후속 입력의 번호를 다시 매겨 야하는지 알고 싶습니다.


컬렉션과 함께 사용하기위한 특정 와이어 형식이 있습니다. 이것은 Scott Hanselman의 블로그에서 논의됩니다.

http://www.hanselman.com/blog/ASPNETWireFormatForModelBindingToArraysListsCollectionsDictionaries.aspx

Phil Haack의 또 다른 블로그 항목은 여기에 대해 설명합니다.

http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx

마지막으로 여기에서 원하는 작업을 정확히 수행하는 블로그 항목 :

http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/


위의 블로그에 링크 된이 접근 방식을 따랐고 일부 사용자에게 도움이 될 수있는 몇 가지 세부 정보를 추가했습니다. 게시물). 또한 순차 ID 유지에 대해 걱정하고 싶지 않았습니다. 시작일과 종료일 목록을 캡처했습니다.

모델보기 :

public class WhenViewModel : BaseViewModel {
    public List<DateViewModel> Dates { get; set; }
    //... Other properties
}

시작 / 종료 날짜보기 모델 :

public class DateViewModel {
    public string DateID { get; set; }
    public DateTime? StartDate { get; set; }
    public DateTime? EndDate { get; set; }
}

그런 다음 페이지에서 사용 (datepicker 사용) :

<div class="grid-8-12 clear" id="DatesBlock">
@{
    foreach (DateViewModel d in Model.Dates) {
        @:<div class="grid-5-12 left clear">
            @Html.Hidden("Dates.Index", d.DateID)
            @Html.Hidden("Dates[" + d.DateID + "].DateID", d.DateID) //ID again to populate the view model
            @Html.TextBox("Dates[" + d.DateID + "].StartDate", 
                          d.StartDate.Value.ToString("yyyy-MM-dd"))
        @:</div>
        @:<div class="grid-5-12">
            @Html.TextBox("Dates[" + d.DateID + "].EndDate", 
                          d.EndDate.Value.ToString("yyyy-MM-dd"))
        @:</div>

        <script type="text/javascript">
            $('input[name="Dates[@d.DateID].StartDate"]')
               .datepicker({ dateFormat: 'yy-mm-dd'});
            $('input[name="Dates[@d.DateID].EndDate"]')
               .datepicker({dateFormat: 'yy-mm-dd'});
        </script>
     }
}
</div>
<a href="#" onclick="AddDatesRow()">Add Dates</a>

위의 @ErikTheVikings 게시물에 링크 된 블로그 게시물이 설명했듯이 컬렉션은 @Html.Hidden("Dates.Index", d.DateID)페이지의 컬렉션에있는 각 항목에 대해 반복되는 숨겨진 요소에 의해 생성됩니다 .

AJAX를 사용하지 않고 임의로 행을 추가하여 데이터를 서버에 다시 게시하고 싶었습니다.이 경우 컬렉션에 하나의 "행"/ 항목의 템플릿을 포함하는 숨겨진 div를 만들었습니다.

숨겨진 "템플릿"행 :

<div id="RowTemplate" style="display: none">
    <div class="grid-5-12 clear">
        @Html.Hidden("Dates.Index", "REPLACE_ID")
        @Html.Hidden("Dates[REPLACE_ID].DateID", "REPLACE_ID") 
        @Html.TextBox("Dates[REPLACE_ID].StartDate", "")
    </div>
    <div class="grid-5-12">
        @Html.TextBox("Dates[REPLACE_ID].EndDate", "")
    </div>
</div>

그런 다음 템플릿을 복제하고 새 행에 사용할 임의의 ID를 제공하고 지금 보이는 복제 된 행을 위의 포함 div에 추가하는 jQuery를 사용했습니다.

프로세스를 완료하는 jQuery :

<script type="text/javascript">
    function AddDatesRow() {
        var tempIndex = Math.random().toString(36).substr(2, 5);
        var template = $('#RowTemplate');
        var insertRow = template.clone(false);
        insertRow.find('input').each(function(){ //Run replace on each input
            this.id = this.id.replace('REPLACE_ID', tempIndex);
            this.name = this.name.replace('REPLACE_ID', tempIndex);
            this.value = this.value.replace('REPLACE_ID', tempIndex);
        });
        insertRow.show();
        $('#DatesBlock').append(insertRow.contents());

        //Attach datepicker to new elements
        $('input[name="Dates['+tempIndex+'].StartDate"]')
            .datepicker({dateFormat: 'yy-mm-dd' });
        $('input[name="Dates['+tempIndex+'].EndDate"]')
            .datepicker({dateFormat: 'yy-mm-dd' });
    }
</script>

결과의 JSFiddle 예 : http://jsfiddle.net/mdares/7JZh4/


다음과 같은 동적 목록이 있습니다.

<ul id="okvedList" class="unstyled span8 editableList">
<li>
    <input data-val="true" data-val-required="The Guid field is required." id="Okveds_0__Guid" name="Okveds[0].Guid" type="hidden" value="2627d99a-1fcd-438e-8109-5705dd0ac7bb">
    --//--
</li>

따라서 행 (li 요소)을 추가하거나 제거 할 때 항목을 다시 정렬해야합니다.

    this.reorderItems = function () {
        var li = this.el_list.find('li');

        for (var i = 0; i < li.length; i++) {
            var inputs = $(li[i]).find('input');

            $.each(inputs, function () {
                var input = $(this);

                var name = input.attr('name');
                input.attr('name', name.replace(new RegExp("\\[.*\\]", 'gi'), '[' + i + ']'));

                var id = input.attr('id');
                input.attr('id', id.replace(new RegExp('_.*__', 'i'), '_' + i + '__'));
            });
        }
    };

this list placed into simple Html.BeginFrom from clientside and like List in action parameter on serverside


I also facing similar problem in the past, and I use KnockoutJS to handle such scenario.

Basically, Knockout send the collection in a JSON string, and I deserialized them in my controller.

For more info : http://learn.knockoutjs.com/#/?tutorial=collections


I got little problem, when i using Chrome Browser and click the back button, and i find the input with type="hidden" when dynamically set values didn't handled properly by the Chrome Browser.

maybe we can change

<input type="hidden" name="Detes.Index" value="2016/01/06" />

to

<div style="display: none">
    <input type="text" name="Detes.Index" value="2016/01/06" />
</div>

Form more info: Chrome doesn't cache hidden form field values for use in browser history http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

참고URL : https://stackoverflow.com/questions/14822615/how-does-mvc-4-list-model-binding-work

반응형