2011-04-18 15 views
5

que sigo la información sobre http://haacked.com/archive/2008/10/23/model-binding-to-a-list.aspx de Phil Haack¿Es posible vincular el modelo a una lista con índices no secuenciales en MVC 3?

Él habla de índices no secuencial:

<form method="post" action="/Home/Create"> 

<input type="hidden" name="products.Index" value="cold" /> 
<input type="text" name="products[cold].Name" value="Beer" /> 
<input type="text" name="products[cold].Price" value="7.32" /> 

<input type="hidden" name="products.Index" value="123" /> 
<input type="text" name="products[123].Name" value="Chips" /> 
<input type="text" name="products[123].Price" value="2.23" /> 

<input type="hidden" name="products.Index" value="caliente" /> 
<input type="text" name="products[caliente].Name" value="Salsa" /> 
<input type="text" name="products[caliente].Price" value="1.23" /> 

<input type="submit" /> 
</form> 

Es esto posible en MVC3 cuando se utiliza la unión con TextBoxFor modelo?
Esta es la manera de hacerlo con índices séquentiel:

@Html.TextBoxFor(m => m[i].Value) 

Si no es posible, es su algo más que pueda hacer si mis índices no serán secuenciales?

+0

Esto sigue siendo una lista secuencial de elementos. Debe proporcionar más contexto en cuanto a lo que está tratando de lograr más allá de solo generar el HTML de indexación alternativo. ¿Está tratando de implementar la reorganización, adición y eliminación de elementos de la colección, sino que no necesita esta sintaxis? –

Respuesta

1

AFAI entiendo que la técnica de índices no secuenciales requeriría agregar campos ocultos para cada valor de índice. Estoy bastante seguro de que el helper Html.TextBoxFor no genera ningún campo oculto adicional. Probablemente pueda lograr esto agregando manualmente los campos ocultos con los índices no secuenciales.

0

Intenté esto y no pude conseguir que funcione con textboxfor. Usé Textbox y especifiqué el nombre.

<form method="post" action="/Home/Create"> 
@{var index = Guid.NewGuid();} 
@Html.Textbox("products["+index +"].Name",Beer) 
@Html.Textbox("products["+index +"].Price",7.32) 
. 
. 
. 
<input type="submit" /> 
</form> 

No necesita un índice oculto para MVC 3.0.

Avísame si esto no funciona Tengo una forma de hacerlo, solo estoy tomando esto de la parte superior de mi cabeza.

+0

Trataré de hacer que esto funcione como mencionas sin tener que usar la entrada oculta para el índice y no puedo hacer que funcione. ¿Tienes un ejemplo de trabajo? –

0

Para no jugar con su vista, la forma más fácil que encontré es seguir esta extensión: BeginCollectionItem.

El proyecto completo está aquí: https://github.com/danludwig/BeginCollectionItem

Pero yo sepa sólo necesita esta clase:

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; 
      } 
     } 
    } 

Cómo utilizarlo en sus Vistas:

<form method="post" action="/Home/Create"> 
    @foreach (var item in Model.Products) {  
     @using (Html.BeginCollectionItem("Products")) 
     { 
      @Html.TextBoxFor(item => item.Name) 
      @Html.TextBoxFor(item => item.Price)    
     } 
    } 
     ... 
     ... 
</form> 

Creo que este es más limpio que jugar con los índices en las vistas ... Aquí está la publicación que explica cómo hacerlo paso por st EP: http://blog.stevensanderson.com/2010/01/28/editing-a-variable-length-list-aspnet-mvc-2-style/

Nuget paquete:http://www.nuget.org/packages/BeginCollectionItem/

Cuestiones relacionadas