c# - net - password mvc
@ Html.HiddenFor no funciona en listas en ASP.NET MVC (12)
Estoy usando un modelo que contiene una Lista como propiedad. Estoy poblando esta lista con elementos que tomo de SQL Server. Quiero que la Lista se oculte en la vista y pase a la acción POST. Más adelante, es posible que desee agregar más elementos a esta lista con jQuery, lo que hace que una matriz no sea adecuada para la expansión más adelante. Normalmente usarías
@Html.HiddenFor(model => model.MyList)
para lograr esta funcionalidad, pero por alguna razón la Lista en POST siempre es nula.
Pregunta muy simple, ¿alguien sabe por qué MVC se comporta así?
¿Qué hay de usar Newtonsoft para deserializar el objeto en una cadena json y luego insertar eso en su campo oculto, por ejemplo ( Model.DataResponse.Entity.Commission es una lista de objetos simples "CommissionRange" como verá en el JSON)
@using (Ajax.BeginForm("Settings", "AffiliateProgram", Model.DataResponse, new AjaxOptions { UpdateTargetId = "result" }))
{
string commissionJson = JsonConvert.SerializeObject(Model.DataResponse.Entity.Commission);
@Html.HiddenFor(data => data.DataResponse.Entity.Guid)
@Html.Hidden("DataResponse_Entity_Commission", commissionJson)
[Rest of my form]
}
Renders como:
<input id="DataResponse_Entity_Commission" name="DataResponse_Entity_Commission" type="hidden" value="[{"RangeStart":0,"RangeEnd":0,"CommissionPercent":2.00000},{"RangeStart":1,"RangeEnd":2,"CommissionPercent":3.00000},{"RangeStart":2,"RangeEnd":0,"CommissionPercent":2.00000},{"RangeStart":3,"RangeEnd":2,"CommissionPercent":1.00000},{"RangeStart":15,"RangeEnd":10,"CommissionPercent":5.00000}]">
En mi caso, hago algunas cosas JS para editar el JSON en el campo oculto antes de publicar de nuevo
En mi controlador, utilizo Newtonsoft nuevamente para deserializar:
string jsonCommissionRange = Request.Form["DataResponse_Entity_Commission"];
List<CommissionRange> commissionRange = JsonConvert.DeserializeObject<List<CommissionRange>>(jsonCommissionRange);
Acabo de encontrarme con este problema y lo resolví simplemente haciendo lo siguiente:
for(int i = 0; i < Model.ToGroups.Count; i++)
{
@Html.HiddenFor(model => Model.ToGroups[i])
}
Al usar un para en lugar de un foreach, el enlace del modelo funcionará correctamente y recogerá todos sus valores ocultos en la lista. Parece la forma más simple de resolver este problema.
Empecé a HiddenFor
el código fuente de HiddenFor
, y creo que el obstáculo que está viendo es que su objeto complejo MyList
no es convertible implícitamente a tipo string
, por lo que el marco trata el valor de su Model
como null
y deja vacío el atributo de value
.
Enfrentado con el mismo problema. Sin for loop, solo publicó el primer elemento de la lista. Después de iterar a través del ciclo, puede mantener la lista completa y publicar con éxito.
@if (Model.MyList!= null)
{
for (int i = 0; i < Model.MyList.Count; i++)
{
@Html.HiddenFor(x => x.MyList[i])
}
}
Es un truco, pero si @Html.EditorFor
o @Html.DisplayFor
funcionan para su lista, si desea asegurarse de que se envía en la solicitud posterior pero no está visible, simplemente puede pegar el estilo usando display: none;
para ocultarlo, por ejemplo:
<div style="display: none;">@Html.EditorFor(model => model.MyList)</div>
HiddenFor no es como un DisplayFor o un EditorFor. No funcionará con colecciones, solo valores únicos.
Puede usar el ayudante Serialize HTML disponible en el proyecto MVC Futures para serializar un objeto a un campo Oculto, o tendrá que escribir el código usted mismo. Una mejor solución es simplemente serializar una identificación de algún tipo y volver a obtener los datos de la base de datos en la devolución de datos.
Me acabo de enterar (después de un par de horas de tratar de averiguar por qué los valores del modelo no volvían al controlador) que oculto debe seguir el Editor para.
A menos que esté haciendo algo diferente, esto es lo que encontré. No cometeré el error otra vez.
En el contexto de un Modelo que contiene una lista de otra clase.
Esto no funcionará:
@{
for (int i = 0; i < Model.Categories.Count; i++)
{
<tr>
<td>
@Html.HiddenFor(modelItem => Model.Categories[i].Id)
@Html.HiddenFor(modelItem => Model.Categories[i].ProductCategoryId)
@Html.HiddenFor(modelItem => Model.Categories[i].CategoryName)
@Html.DisplayFor(modelItem => Model.Categories[i].CategoryName)
</td>
<td>
@Html.HiddenFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
@Html.EditorFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
@Html.ValidationMessageFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
</td>
<td style="text-align: center">
@Html.HiddenFor(modelItem => Model.Categories[i].IsSelected)
@Html.EditorFor(modelItem => Model.Categories[i].IsSelected)
</td>
</tr>
}
}
Donde como esto TENDRA ......
for (int i = 0; i < Model.Categories.Count; i++)
{
<tr>
<td>
@Html.HiddenFor(modelItem => Model.Categories[i].Id)
@Html.HiddenFor(modelItem => Model.Categories[i].ProductCategoryId)
@Html.HiddenFor(modelItem => Model.Categories[i].CategoryName)
@Html.DisplayFor(modelItem => Model.Categories[i].CategoryName)
</td>
<td>
@Html.EditorFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
@Html.HiddenFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
@Html.ValidationMessageFor(modelItem => Model.Categories[i].DailyPurchaseLimit)
</td>
<td style="text-align: center">
@Html.EditorFor(modelItem => Model.Categories[i].IsSelected)
@Html.HiddenFor(modelItem => Model.Categories[i].IsSelected)
</td>
</tr>
}
Otra forma posible de corregir esto sería asignarle a cada objeto de su Lista una ID, luego usar @Html.DropDownListFor(model => model.IDs)
y rellenar una matriz que contenga los ID.
Otra opción sería:
<input type="hidden" value=@(string.Join(",", Model.MyList)) />
Puedes echarle un vistazo a esta solution .
Ponga solo HiddenFor dentro de EditorTemplate.
Y en su Vista, ponga esto: @Html.EditorFor(model => model.MyList)
Debería funcionar
tal vez tarde, pero creé el método de extensión para los campos ocultos de la colección (con elementos de tipo de datos simples):
Asi que aqui esta:
/// <summary>
/// Returns an HTML hidden input element for each item in the object''s property (collection) that is represented by the specified expression.
/// </summary>
public static IHtmlString HiddenForCollection<TModel, TProperty>(this HtmlHelper<TModel> html, Expression<Func<TModel, TProperty>> expression) where TProperty : ICollection
{
var model = html.ViewData.Model;
var property = model != null
? expression.Compile().Invoke(model)
: default(TProperty);
var result = new StringBuilder();
if (property != null && property.Count > 0)
{
for(int i = 0; i < property.Count; i++)
{
var modelExp = expression.Parameters.First();
var propertyExp = expression.Body;
var itemExp = Expression.ArrayIndex(propertyExp, Expression.Constant(i));
var itemExpression = Expression.Lambda<Func<TModel, object>>(itemExp, modelExp);
result.AppendLine(html.HiddenFor(itemExpression).ToString());
}
}
return new MvcHtmlString(result.ToString());
}
El uso es tan simple como:
@Html.HiddenForCollection(m => m.MyList)
Html.HiddenFor
está diseñado para un solo valor. Tendrá que serializar su lista de alguna manera antes de crear el campo oculto.
Por ejemplo, si su lista es de tipo cadena, puede unir la lista a una lista separada por comas, luego dividir la lista después de la publicación en su controlador.