#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. Спасибо. Мне придется усвоить то, что вы написали. Спасибо за ответ.