0

Je dois transmettre des données créées dynamiquement à partir d'une vue partielle au contrôleur lors de la soumission à partir du formulaire principal.Passage des données de collection de la vue partielle au contrôleur

est ici l'action qui retourne la vue partielle:

[HttpGet] 
public virtual PartialViewResult AddItem() 
{ 
    var item = new QuotedItem(); 
    ViewBag.StockID = new SelectList(db.StockItems.OrderBy(s => s.Name), "StockID", "Name"); 
    return PartialView("EditorTemplates/QuotedItem", item); 
} 

Voici le EditorTemplate pour QuotedItem:

@model StockSystem.Models.QuotedItem 

<div id="itemRow"> 

    <span> 
     @Html.DropDownListFor(model => model.StockID, null) 
     @Html.ValidationMessageFor(model => model.StockID, "", new { @class = "text-danger" }) 
    </span> 
    <span> 
     @Html.EditorFor(model => model.Price) 
     @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" }) 
    </span> 
    <span> 
     @Html.EditorFor(model => model.Quantity) 
     @Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" }) 
    </span> 

    <a href="#" class="deleteSmall"></a> 

</div> 

Voici la vue:

@model StockSystem.Models.Quote 

@{ 
    ViewBag.Title = "Create"; 
} 

<h2>New Quote for @ViewBag.Customer</h2> 

<hr /> 
@using (Html.BeginForm()) 
{ 
    @Html.AntiForgeryToken() 
    @Html.ValidationSummary(true, "", new { @class = "text-danger" }) 
    @Html.Hidden("CustomerID", (object)ViewBag.CustomerID) 

    <div class="addItem"> 
     @Ajax.ActionLink(" ", "AddItem", 
     new AjaxOptions 
     { 
      UpdateTargetId = "editorRows", 
      InsertionMode = InsertionMode.InsertAfter, 
      HttpMethod = "GET" 
     }) 
    </div> 

    <div id="editorRows"> 
     @Html.EditorFor(q => q.QuotedItems) 
    </div> 

    <p></p> 

    <div> 
     <input class="add" type="submit" value="" /> 
     <a class="back" href="@Url.Action("Index", "Quotes", new { id = ViewBag.CustomerID })"></a> 
    </div> 
} 

Voici Créer action:

public ActionResult Create(int id) 
{ 
    var customer = db.Customers.Find(id); 
    ViewBag.CustomerID = id; 
    ViewBag.Customer = customer.CustomerName; 
    var quote = new Quote() { QuotedItems = new List<QuotedItem>() }; 
    return View(quote); 
} 

est ici le modèle EF pour QuotedItem:

public partial class QuotedItem 
{ 
    public int QuotedItemID { get; set; } 
    public int QuoteID { get; set; } 
    public int StockID { get; set; } 
    public int Quantity { get; set; } 
    public decimal Price { get; set; } 

    public virtual Quote Quote { get; set; } 
    public virtual StockItem StockItem { get; set; } 
} 

Et Quote:

public partial class Quote 
{ 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors")] 
    public Quote() 
    { 
     this.QuotedItems = new HashSet<QuotedItem>(); 
    } 

    public int QuoteID { get; set; } 
    public int CustomerID { get; set; } 
    public int UserID { get; set; } 
    public System.DateTime QuoteDate { get; set; } 
    public string QuoteRef { get; set; } 

    public virtual Customer Customer { get; set; } 
    [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly")] 
    public virtual ICollection<QuotedItem> QuotedItems { get; set; } 
    public virtual User User { get; set; } 
} 

je peux ajouter des éléments à la page mais ils ne sont pas ajoutés à la citation sur soumettre.

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote) //, List<QuotedItem> items 
{ 
    if (ModelState.IsValid) 
    { 
     //quote.QuotedItems is empty, how do I bind this data and save to database?   
     db.Quotes.Add(quote); 
     db.SaveChanges(); 
     return RedirectToAction("Index", new { id = quote.CustomerID }); 
    } 

    return View(quote); 
} 

La collection n'est pas envoyée au contrôleur. Comment cela est-il fait?

Merci

Edit: Je pensais à essayer cela:

[HttpPost] 
[ValidateAntiForgeryToken] 
public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote, List<QuotedItem> items) 
{ 
    if (ModelState.IsValid) 
    { 
     quote.QuotedItems = items; 
     db.Quotes.Add(quote); 
     db.SaveChanges(); 
     return RedirectToAction("Index", new { id = quote.CustomerID }); 
    } 

    return View(quote); 
} 

Mais je pensais qu'il doit y avoir une meilleure façon. Si j'essayais cette approche, je ne suis toujours pas sûr de savoir comment l'envoyer au contrôleur, je suppose que c'est un paramètre dans Html.BeginForm()? Je suis assez nouveau pour MVC et je suis encore en train de me familiariser avec les conventions. En utilisant l'attribut Bind dans votre signature de méthode, vous empêchez la propriété QuotedItems d'être publiée dans l'action du contrôleur.

Répondre

0

public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef")] Quote quote) 

Ajout du nom de la propriété QuotedItems à inclure la liste devrait résoudre ceci:

public ActionResult Create([Bind(Include = "QuoteID,CustomerID,UserID,QuoteDate,QuoteRef,QuotedItems")] Quote quote) 

EDIT

Sans voir votre éditeur QuotedItem modèle, il est difficile de dire à coup sûr, mais Il semblerait que votre problème soit que chaque élément ajouté à votre liste n'ait pas d'identifiant unique sur les éléments qui composent cet élément. Sans cela, le classeur aura du mal à trouver quel élément appartient à quel objet de la collection.

Jetez un oeil à ces deux articles et voir si elles aident:

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

https://www.mattlunn.me.uk/blog/2014/08/how-to-dynamically-via-ajax-add-new-items-to-a-bound-list-model-in-asp-mvc-net/

Edit 2

Chaque élément de votre modèle doit être donné un identifiant unique , un index est un bon moyen de le faire, tout comme les GUID d'éléments (si vous les avez); mais tant que chaque ID d'élément est unique à cet élément, cela devrait fonctionner.

@model StockSystem.Models.QuotedItem 

<div id="itemRow"> 
<span> 
    @Html.DropDownListFor(model => model.StockID, null) 
    @Html.ValidationMessageFor(model => model.StockID, "", new { @class = "text-danger" }) 
</span> 
<span> 
    @Html.EditorFor(model => model.Price, new { htmlAttributes = new { id = $"[{YOURINDEX}].Price" } }) 
    @Html.ValidationMessageFor(model => model.Price, "", new { @class = "text-danger" }) 
</span> 
<span> 
    @Html.EditorFor(model => model.Quantity, new { htmlAttributes = new { id = $"[{YOURINDEX}].Quantity" } }) 
    @Html.ValidationMessageFor(model => model.Quantity, "", new { @class = "text-danger" }) 
</span> 

<a href="#" class="deleteSmall"></a> 

Dans le code ci-dessus la valeur [YOURINDEX] aurait besoin d'être incrémentée pour chaque nouvel élément ajouté à la collection.

La façon dont vous implémentez et incrémentez cet index dépend de vous, mais je vous suggère de lire les deux articles auxquels je me suis déjà connecté pour comprendre pourquoi cela est nécessaire.

+0

J'ai déjà essayé ça. La collection finit toujours par être vide. – Dom

+0

initialisez-vous la collection 'QuoteItems' dans l'action HttpGet Create? –

+0

Guy - J'ai modifié ma question pour afficher l'action Créer. – Dom