getJson не вызывает JsonResult для моделей, отображаемых с помощью PartialView
Итак, у меня есть это приложение в ASP MVC 3. В моей базе данных есть две таблицы: Comenzi и DetaliiComenzi с отношением один-ко-многим (и Link-to-Sql) - в моем приложении я хочу, чтобы мои пользователи покупали некоторые продукты, делая oder(хранится в таблице comenzi) и для этого заказа список продуктов, которые он хочет купить (будет сохранен в DetaliiComenzi с Order.id в качестве внешнего ключа). По сути, после того, как я создаю новую запись для Comenzi, я хочу иметь возможность составить список продуктов для этого заказа (что-то вроде графика магазина, но пользователь будет выбирать свои продукты в представлении, добавляя, сколько продуктов ему нравится),
Я использовал метод Стива Сандерсона для редактирования (и создания) списка переменной длины.
- Вот модель, для которой я создаю список.
Когда я выбираю один продукт для заказа, я должен сначала выбрать группу (Grupa), к которой он принадлежит, из выпадающего списка (используя ListaGrupe), а затем из второго выпадающего списка (ListaProduse) продукт из этой конкретной группы продуктов, которые я выбрал в первый выпадающий список.
public class Comd
{
public string Grupa { get; set; }
public string Produs { get; set; }
public string Cantitate { get; set; }
public string Pret { get; set;}
public string TVA { get; set; }
public string Total { get; set; }
public List<SelectListItem> ListaGrupe
{
get;
set;
}
public List<SelectListItem> ListaProduse
{
get;
set;
}
}
- Контроллер:
public ActionResult ComandaDetaliu(string id)
{
Comd model = new Comd();
IProduseRepository _prod = new ProduseRepository();
model.ListaGrupe = _listecomanda.GetGrupe();
string first = model.ListaGrupe[0].Value;
model.ListaProduse = _listecomanda.GetProduse(first);
string pret = _prod.GetByDenumire(model.ListaProduse[0].Text).pret.ToString();
model.Pret = pret;
double fr = 0.24;
model.TVA = fr.ToString();
var data = new[] { model };
return View(data);
}
-- Вид
<%@ Page Title="" Language="C#" MasterPageFile="~/Views/Shared/Site.Master" Inherits="System.Web.Mvc.ViewPage<IEnumerable<InMVC3.Models.Comd>>" %>
<%@ Import Namespace="InMVC3.Helpers"%>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Comanda numarul: <%: RouteData.Values["id"].ToString()%></h2>
<% using(Html.BeginForm()) { %>
<div id="editorRows">
<% foreach (var item in Model)
Html.RenderPartial("ProduseEditor", item);
%>
</div>
<%= Html.ActionLink("Adauga alt produs", "Add", null, new { id = "addItem" }) %>
<input type="submit" value="Finished" />
<% } %>
- Частичное представление "Редактор продуктов"
<%@ Control Language="C#" Inherits="System.Web.Mvc.ViewUserControl<InMVC3.Models.Comd>" %>
<%@ Import Namespace="InMVC3.Helpers" %>
<div class="editorRow">
<script type="text/javascript">
$(document).ready(function () {
$("#Grupa").change(function () {
var url = '<%= Url.Content("~/") %>' + "Comenzi/ForProduse";
var ddlsource = "#Grupa";
var ddltarget = "#Produs";
$.getJSON(url, { id: $(ddlsource).val() }, function (data) {
$(ddltarget).empty();
$.each(data, function (index, optionData) {
$(ddltarget).append("<option value='" + optionData.Value + "'>" + optionData.Text + "</option>");
});
});
});
});
</script>
<% using(Html.BeginCollectionItem("comds")) { %>
Grupa: <%= Html.DropDownListFor(x => x.Grupa, Model.ListaGrupe) %>
Produsul: <%= Html.DropDownListFor(x => x.Produs, Model.ListaProduse) %>
Cantitate: <%=Html.TextBoxFor(x=>x.Cantitate) %>
Pret: <%=Html.DisplayFor(x => x.Pret, new { size = 4})%>
TVA: <%= Html.DisplayFor(x=>x.TVA) %>
Total: <%=Html.DisplayFor(x=>x.Total) %>
<a href="#" class="deleteRow">Sterge</a>
<% } %>
- И метод JsonResult
public JsonResult ForProduse(string id)
{
throw new NotSupportedException();
JsonResult result = new JsonResult();
var produsele = _listecomanda.GetProduse(id);
result.Data = produsele;
result.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return result;
}
Все, что мне нужно знать, - это как вызвать действие JsonResult, потому что это то, что не работает, чтобы при изменении выбранного значения в первом раскрывающемся списке динамически изменять и второе. Конечно, мне также нужно изменить и другие свойства, но после того, как я получу, как заставить getJson работать.
Если вам нужно больше деталей, пожалуйста, сообщите мне.
ОБНОВЛЕНИЕ 1:
- Помощник
public static class HtmlPrefixScopeExtensions
{
private const string idsToReuseKey = "__htmlPrefixScopeExtensions_IdsToReuse_";
public static IDisposable BeginCollectionItem(this HtmlHelper html, string collectionName)
{
var idsToReuse = GetIdsToReuse(html.ViewContext.HttpContext, collectionName);
string itemIndex = idsToReuse.Count > 0 ? idsToReuse.Dequeue() : Guid.NewGuid().ToString();
// autocomplete="off" is needed to work around a very annoying Chrome behaviour whereby it reuses old values after the user clicks "Back", which causes the xyz.index and xyz[...] values to get out of sync.
html.ViewContext.Writer.WriteLine(string.Format("<input type=\"hidden\" name=\"{0}.index\" autocomplete=\"off\" value=\"{1}\" />", collectionName, html.Encode(itemIndex)));
return BeginHtmlFieldPrefixScope(html, string.Format("{0}[{1}]", collectionName, itemIndex));
}
public static IDisposable BeginHtmlFieldPrefixScope(this HtmlHelper html, string htmlFieldPrefix)
{
return new HtmlFieldPrefixScope(html.ViewData.TemplateInfo, htmlFieldPrefix);
}
private static Queue<string> GetIdsToReuse(HttpContextBase httpContext, string collectionName)
{
// We need to use the same sequence of IDs following a server-side validation failure,
// otherwise the framework won't render the validation error messages next to each item.
string key = idsToReuseKey + collectionName;
var queue = (Queue<string>)httpContext.Items[key];
if (queue == null) {
httpContext.Items[key] = queue = new Queue<string>();
var previouslyUsedIds = httpContext.Request[collectionName + ".index"];
if (!string.IsNullOrEmpty(previouslyUsedIds))
foreach (string previouslyUsedId in previouslyUsedIds.Split(','))
queue.Enqueue(previouslyUsedId);
}
return queue;
}
private class HtmlFieldPrefixScope : IDisposable
{
private readonly TemplateInfo templateInfo;
private readonly string previousHtmlFieldPrefix;
public HtmlFieldPrefixScope(TemplateInfo templateInfo, string htmlFieldPrefix)
{
this.templateInfo = templateInfo;
previousHtmlFieldPrefix = templateInfo.HtmlFieldPrefix;
templateInfo.HtmlFieldPrefix = htmlFieldPrefix;
}
public void Dispose()
{
templateInfo.HtmlFieldPrefix = previousHtmlFieldPrefix;
}
}
}
ОБНОВЛЕНИЕ У меня теперь есть другая проблема. Когда я публикую этот список в actiont, я получаю следующую ошибку в операторе foreach внутри действия контроллера: ссылка на объект не установлена для экземпляра объекта.
- Действие контроллера
[HttpPost]
public ActionResult ComandaDetaliu(IEnumerable<Comd> comenzi)
{
if (ModelState.IsValid)
{
foreach (var item in comenzi)
{
detalii_comenzi det = new detalii_comenzi();
det.id_comanda = Convert.ToInt32(RouteData.Values["id"].ToString());
det.id_produs = Convert.ToInt32(item.Produs);
det.cantitate_comandata = Convert.ToDecimal(item.Cantitate);
det.cantitate_livrata = 0;
det.pret =Convert.ToDecimal(item.Pret);
det.tvap = Convert.ToDecimal(item.TVA);
}
return RedirectToAction("Index");
}
return View(comenzi);
}
1 ответ
Ваша проблема заключается в дублировании идентификаторов - в каждой строке есть раскрывающийся список с идентификатором "Grupa", поэтому ваш селектор jquery будет соответствовать раскрывающимся спискам в каждой строке.
Вам нужно добавить префикс к элементам управления - есть несколько способов добиться этого - поиск "префикс поля mvc3" поднимает несколько других вопросов:
- Как определить префикс поля формы в ASP.NET MVC
- ASP.MVC 3 Razor Добавить модель префикса в расширении Html.PartialView
- Частичные представления ASP.NET MVC: префиксы входных имен
Большинство из них сосредоточены на отображении при публикации формы, но та же проблема относится и к вашему javascript.
Вы можете просто обновить идентификаторы в вашем скрипте до чего-то вроде "#@(ViewBag.Prefix)Grupa"
, но лучшим подходом было бы использовать классы вместо идентификаторов в вашем селекторе и сделать скрипт повторно используемым - что-то вроде:
ddlSource = this;
ddlDest = this.Parent().find(".produs");