MVC 3: свойство AJAX post list модели

#c# #asp.net-mvc-3 #razor

#c# #asp.net-mvc-3 #бритва

Вопрос:

У меня возникли проблемы с отправкой вызова ajax с моей моделью, у которой есть список.

Моя модель:

 public class MyListItem
{
    public int Id { get; set; }
    public string Value { get; set; }
}

public class MyModel
{
    public int Integer { get; set; }
    public string Str { get; set; }
    public List<MyListItem> MyList { get; set; }        

    public MyModel()
    {
        Str = "Initial";
        Integer = 1;
    }
}
 

на мой взгляд, я пытаюсь отобразить элементы списка myList как:

     <div>
    @{
            if (Model.MyList != null)
            { 
                int i = 0;
                foreach (var item in Model.MyList)
                {                       
                    <label>@item.Value</label>
                    @Html.Hidden("MyList["   i   "].Id", item.Id);
                    @Html.TextArea("MyList["   i   "].Value", item.Value, 1, 10, new { Value = item.Value });
                    <div />

                    i  ;
                }
            }
    }
</div>
 

это представление является частичным представлением, и оно вызывается из «основного» представления следующим образом:

 <form id="mine2">
    @{Html.RenderPartial("Test2", Model);}
</form>
 

Мой пост ajax:

     function OnAddToListAjax() {
    var actionUrl = '@Url.Action("AddToList", "Test1")';
    var alist = @Html.Raw(Json.Encode(Model));

    try
    {
        $.ajax(
        {
            url: actionUrl,
            type: "POST",
            dataType: "HTML",
            contentType: 'application/json',
            processData: false,
            //data: JSON.stringify({myModel: existing, list: alist}),
            data: JSON.stringify({myModel: alist}),
            traditional: true,
            success: function(result) {
                //alert(result);
                $('#mine2').html(result);
            },
            error: function (req, status, error) {
                HandleError(req);
            }
        });
    }
    catch (err)
    {
        alert(err);
    }
}
 

мой контроллер:

         [HttpPost]
    public ActionResult AddToList(MyModel myModel)//, MyList list)
    {
        try
        {

            //var list = new MyList();
            if (myModel.MyList == null)
                myModel.MyList = new MyList();
            myModel.Str  = " Changed";

            //throw new Exception("This is broken!");
            myModel.MyList.Add(new MyListItem { Id = myModel.MyList.Count, Value = string.Format("Item {0}", myModel.MyList.Count) });
            //myModel.MyList = list;

            return PartialView("Test2", myModel);
        }
        catch (Exception ex)
        {
            myModel.ErrorModel = new ErrorModel() { ErrorDetails = "Error adding to list", ErrorString = ex.Message };
            return PartialView("Test2", myModel);

        }
    }
 

эта концепция отлично работает для меня при использовании прямого свойства моей модели. например, если я попытаюсь установить / получить свойство Str. Однако для элементов myList они, похоже, никогда не сериализуются должным образом в команде Json. Он сохраняет значения, которые были частью исходной модели. т.е. в первый раз, когда я вызываю это, myList имеет значение null, поэтому я создаю его и возвращаю как часть результата действия. При этом отображаются значения ok. Однако, если я вручную отредактирую значение и повторно опубликую его, опубликованное значение будет таким же, как было первоначально получено.

Я полагаю, что это, возможно, как-то связано с именем, которое я даю текстовой области, и оно не может быть разрешено должным образом. Используя Firebug, источником для одной из заданных текстовых областей является:

 <textarea id="MyList_0__Value" rows="1" name="MyList[0].Value" cols="10" value="Item 0">Item 0</textarea>
 

Итак, я пытаюсь определить, почему кодировка моей модели не имеет обновленных (отредактированных) значений.

TIA

Ответ №1:

Я бы рекомендовал вам использовать шаблоны редактора. Таким образом, вы могли бы заменить цикл foreach, который вы написали в своем частичном представлении, следующим образом:

 @model MyModel
<div>
    @if (Model.MyList != null)
    {
        @Html.EditorFor(x => x.MyList)
    }
</div>
 

а затем определите шаблон редактора для ит, который будет отображаться для каждого элемента списка ( ~/Views/Test1/EditorTemplates/MyListItem.cshtml или ~/Views/Shared/EditorTemplates/MyListItem.cshtml ):

 @model MyListItem
@Html.LabelFor(x => x.Value, Model.Value)
@Html.HiddenFor(x => x.Id);
@Html.TextAreaFor(x => x.Value, 1, 10);
 

Шаблон редактора позаботится о правильном присвоении имен полям ввода, чтобы связующее устройство модели по умолчанию правильно десериализовало их обратно.

Теперь в вашем основном представлении вы также можете использовать шаблон редактора вместо частичного:

 @model MyModel
@using (Html.BeginForm("AddToList", "Test1", FormMethod.Post, new { id = "myForm" }))
{
    @Html.EditorForModel()
}
 

и тогда шаблон редактора, который я показал ранее, будет размещен по соглашению в ~/Views/Test1/EditorTemplates/MyModel.cshtml or ~/Views/Shared/EditorTemplates/MyModel.cshtml .

Хорошо, пока все хорошо. Последний шаг — отправить запрос AJAX. Это можно сделать в отдельном файле javascript:

 var myForm = $('#myForm');
$.ajax({
    url: myForm.attr('action'),
    type: myForm.attr('method'),
    data: myForm.serialize(),
    success: function(result) {
        $('#mine2').html(result);
    },
    error: function (req, status, error) {
        HandleError(req);
    }
});
 

Чистый и простой.

Теперь, когда мы очистили представление и javascript, нам нужно очистить действие контроллера, из-за которого возникла ваша первоначальная проблема. Итак, в вашем действии контроллера вы пытаетесь изменить опубликованные значения. Проблема заключается в том, что помощники HTML используют значения ModelState при привязке, а затем используют модель. Это сделано специально. Таким образом, значения, которые вы вводите в свою модель, полностью игнорируются помощниками, и вы видите старые значения, которые были отправлены в действие контроллера. Сначала вам нужно будет удалить их из состояния модели.

Комментарии:

1. Спасибо. Мне придется усвоить то, что вы написали. Спасибо за ответ.