2017-07-16 1 views
0

J'ai récemment rencontré un comportement avec MVC4 que j'espère avoir un peu de perspective sur. Le comportement dans mon projet actuel utilise des objets plus complexes, mais j'ai été capable de le reproduire avec des objets simples, ce que j'utilise dans cette question. Ma situation est la suivante:MVC Collection éléments manquants sur le poste

  1. J'ai une vue qui utilise une collection de chaînes comme son modèle.
  2. J'appelle "EditorFor" pour afficher chaque chaîne de la collection.
  3. Dans le contrôleur, je remplis le modèle avec 7 éléments de chaîne et le passe à la vue.
  4. La vue rend les 7 éléments.
  5. J'utilise jquery pour supprimer le 2ème élément de la collection du DOM.
  6. Je clique sur Envoyer pour poster.
  7. Je vérifie le contenu de mon modèle de retour affiché et il ne contient que le premier élément de la liste. Je m'attendais à avoir 6 éléments dans la liste (7 minutes celui que j'ai retiré du DOM).

Le code de la situation décrite est la suivante:

Voir

@model ICollection<string> 

@{ 
    ViewBag.Title = "Home Page"; 
} 

@using (Html.BeginForm("Index", "Home", FormMethod.Post)) 
{ 
    @Html.EditorFor(x => x); 
    <input id="btnSubmit" type="submit" value="Submit" /> 
} 

Contrôleur

[HttpGet] 
public ActionResult Index() 
{ 
    List<string> vm = new List<string> 
    { 
     "one", 
     "two", 
     "threE", 
     "four", 
     "five", 
     "six", 
     "seven" 
    }; 

    return View(vm); 
} 

[HttpPost] 
public ActionResult Index(List<string> vm) 
{ 
    return View(vm); 
} 

Merci à tous ceux qui dépanne avec cela. Au plaisir d'augmenter ma compréhension de MVC!

Répondre

0

En utilisant les informations contenues dans la réponse que Masound affichée, j'ai pu créer une solution à ce problème. Il s'avère que le problème est que j'utilisais une collection séquentielle où chaque index repose sur le précédent. Ainsi, lorsque j'ai supprimé un élément de la collection, j'ai perdu le lien vers les autres éléments qui le traitent.

La solution consiste à utiliser une collection non séquentielle où l'index est stocké en tant que champ masqué dans le DOM. En utilisant cette méthode, MVC sait où se situe chaque index et peut recréer la collection en post avec tous les éléments.

Une description de la solution est la suivante:

  1. J'ai une vue qui utilise une collection d'objets d'essai comme modèle.
  2. J'ai une classe auxiliaire qui génère l'index d'un objet dans une collection.
  3. J'appelle "EditorFor" pour afficher chaque objet Test et son index dans la collection.
  4. Dans le contrôleur, je remplis le modèle avec 7 éléments de chaîne et le passe à la vue.
  5. La vue rend les 7 éléments.
  6. J'utilise jquery pour supprimer le 2ème élément de la collection du DOM.
  7. Je clique sur Envoyer pour poster.
  8. Je vérifie le contenu de mon modèle de retour posté et il ne contient que 6 articles, ce qui est ce que j'attends.
  9. Je fais une redirection vers la méthode Get pour actualiser la liaison de l'état du modèle. J'ai remarqué un comportement où l'indexation se lierait au mauvais élément de la collection. Donc, si vous envisagez de recharger la même vue, je vous recommande d'implémenter cette solution pour éviter les comportements inattendus.

Le code de cette solution est la suivante:

Test.cs

using System; 
using System.Collections.Generic; 
using System.ComponentModel.DataAnnotations; 
using System.Linq; 
using System.Web; 

namespace WebApplication2.Models 
{ 
    public class Test 
    { 
     [Required(ErrorMessage="Required")] 
     public string str {get; set;} 
    } 
} 

Test.cshtml

@model WebApplication2.Models.Test 
@using WebApplication2.Helpers 

@{ 
    ViewBag.Title = "Test"; 
} 

<div id="@Model.str"> 
    @Html.TextBoxFor(x => x.str) 
    @Html.ValidationMessageFor(x => x.str) 
    @Html.HiddenIndexerInputForModel() 
</div> 

Index.cshtml

@model ICollection<WebApplication2.Models.Test> 

@{ 
    ViewBag.Title = "Home Page"; 
} 

@using (Html.BeginForm("Index", "Home", FormMethod.Post)) 
{ 
    @Html.EditorFor(x => x) 
    <input id="btnSubmit" type="submit" value="Submit" /> 
} 

contrôleur

[HttpGet] 
public ActionResult Index() 
{ 
    List<Test> vm = (List<Test>)Session["Test"]; 

    if (vm == default(List<Test>)) 
    { 
     vm = new List<Test> 
     { 
      new Test { str="one"}, 
      new Test { str="two"}, 
      new Test { str="three"}, 
      new Test { str="four"}, 
      new Test { str="five"}, 
      new Test { str="six"}, 
      new Test { str="seven"} 
     }; 
     Session.Add("Test", vm); 
    }      

    return View(vm); 
} 

[HttpPost] 
public ActionResult Index(List<Test> vm) 
{ 
    Session.Add("Test", vm); 
    return RedirectToAction("Index"); 
} 

HtmlHelper.cs - Aide a été prise à partir d'ici: http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx/

public static class ListModelBindingExtensions 
{ 
    static Regex _stripIndexerRegex = new Regex(@"\[(?<index>\d+)\]", RegexOptions.Compiled); 

    public static string GetIndexerFieldName(this TemplateInfo templateInfo) 
    { 
     string fieldName = templateInfo.GetFullHtmlFieldName("Index"); 
     fieldName = _stripIndexerRegex.Replace(fieldName, string.Empty); 
     if (fieldName.StartsWith(".")) 
     { 
      fieldName = fieldName.Substring(1); 
     } 
     return fieldName; 
    } 

    public static int GetIndex(this TemplateInfo templateInfo) 
    { 
     string fieldName = templateInfo.GetFullHtmlFieldName("Index"); 
     var match = _stripIndexerRegex.Match(fieldName); 
     if (match.Success) 
     { 
      return int.Parse(match.Groups["index"].Value); 
     } 
     return 0; 
    } 

    public static MvcHtmlString HiddenIndexerInputForModel<TModel>(this HtmlHelper<TModel> html) 
    { 
      string name = html.ViewData.TemplateInfo.GetIndexerFieldName(); 
      object value = html.ViewData.TemplateInfo.GetIndex(); 
      string markup = String.Format(@"<input type=""hidden"" name=""{0}"" value=""{1}"" />", name, value); 
      return MvcHtmlString.Create(markup); 
    } 
} 

Merci à tous ceux qui ont contribué à l'arrivée de cette solution!

0

C'est un problème d'indexation.

@model ICollection<string>  
@{ 
    ViewBag.Title = "Home Page"; 
} 

@using (Html.BeginForm("Index", "Home", FormMethod.Post)) { 
    @for(int index = 0; index < Mode.Count; i++) { 
     @Html.EditorFor(x => x[index]) 
    } 
    <input id="btnSubmit" type="submit" value="Submit" /> 
} 

La partie difficile serait de gérer les index restants si le plan est de supprimer des éléments.