J'ai un ViewModel qui a un objet complexe en tant que membre. L'objet complexe a 4 propriétés (toutes les chaînes). J'essaie de créer une vue partielle réutilisable dans laquelle je peux passer dans l'objet complexe et lui demander de générer le code HTML avec des aides HTML pour ses propriétés. Cela fonctionne très bien. Cependant, lorsque je soumets le formulaire, le classeur de modèle ne mappe pas les valeurs sur le membre de ViewModel, je ne reçois donc rien du côté serveur. Comment puis-je lire les valeurs qu'un utilisateur tape dans les aides HTML pour l'objet complexe.
ViewModel
public class MyViewModel
{
public string SomeProperty { get; set; }
public MyComplexModel ComplexModel { get; set; }
}
MyComplexModel
public class MyComplexModel
{
public int id { get; set; }
public string Name { get; set; }
public string Address { get; set; }
....
}
Manette
public class MyController : Controller
{
public ActionResult Index()
{
MyViewModel model = new MyViewModel();
model.ComplexModel = new MyComplexModel();
model.ComplexModel.id = 15;
return View(model);
}
[HttpPost]
public ActionResult Index(MyViewModel model)
{
// model here never has my nested model populated in the partial view
return View(model);
}
}
Vue
@using(Html.BeginForm("Index", "MyController", FormMethod.Post))
{
....
@Html.Partial("MyPartialView", Model.ComplexModel)
}
Vue partielle
@model my.path.to.namespace.MyComplexModel
@Html.TextBoxFor(m => m.Name)
...
comment puis-je lier ces données lors de la soumission du formulaire afin que le modèle parent contienne les données saisies sur le formulaire Web à partir de la vue partielle?
merci
EDIT: J'ai compris que je devais ajouter "ComplexModel". à tous les noms de mon contrôle dans la vue partielle (zones de texte) pour qu'il mappe sur l'objet imbriqué, mais je ne peux pas transmettre le type ViewModel à la vue partielle pour obtenir cette couche supplémentaire, car elle doit être générique pour accepter plusieurs ViewModel. les types. Je pourrais simplement réécrire l'attribut name avec javascript, mais cela me semble excessivement ghetto. Comment puis-je faire cela?
EDIT 2: Je peux définir de manière statique l'attribut name avec un nouveau {Name = "ComplexModel.Name"}. Je pense donc que je suis en affaires sauf si quelqu'un a une meilleure méthode?
Vous pouvez passer le préfixe au partiel en utilisant
@Html.Partial("MyPartialView", Model.ComplexModel,
new ViewDataDictionary { TemplateInfo = new TemplateInfo { HtmlFieldPrefix = "ComplexModel" }})
qui va perpendiculer le préfixe à vous contrôles attribut name
de sorte que <input name="Name" ../>
deviendra <input name="ComplexModel.Name" ../>
et se liera correctement à typeof MyViewModel
sur post back
Modifier
Pour que ce soit un peu plus facile, vous pouvez l'encapsuler dans un helper HTML
public static MvcHtmlString PartialFor<TModel, TProperty>(this HtmlHelper<TModel> helper, Expression<Func<TModel, TProperty>> expression, string partialViewName)
{
string name = ExpressionHelper.GetExpressionText(expression);
object model = ModelMetadata.FromLambdaExpression(expression, helper.ViewData).Model;
var viewData = new ViewDataDictionary(helper.ViewData)
{
TemplateInfo = new System.Web.Mvc.TemplateInfo
{
HtmlFieldPrefix = string.IsNullOrEmpty(helper.ViewData.TemplateInfo.HtmlFieldPrefix) ?
name : $"{helper.ViewData.TemplateInfo.HtmlFieldPrefix}.{name}"
}
};
return helper.Partial(partialViewName, model, viewData);
}
et l'utiliser comme
@Html.PartialFor(m => m.ComplexModel, "MyPartialView")
Je suis tombé dans la même situation et avec l'aide de tels messages informatifs, j'ai modifié mon code partiel pour que le préfixe soit généré dans les éléments d'entrée générés par une vue partielle.
J'ai utilisé l'assistant Html.partial en donnant le nom de vue partielle et l'objet de ModelType ainsi qu'une instance d'objet ViewDataDictionary avec le préfixe de champ Html au constructeur de Html.partial.
Il en résulte une requête GET "xyz url" de "Main View" et un rendu partiel de la vue à l'intérieur avec des éléments d'entrée générés avec le préfixe, par exemple. Plus tôt, Name = "Title" devient maintenant Name = "MySubType.Title" dans l'élément HTML respectif et identique pour le reste des éléments d'entrée de formulaire.
Le problème est survenu lorsque la demande POST est adressée à "xyz url", en espérant que le formulaire rempli est enregistré dans ma base de données. Mais MVC Modelbinder n'a pas lié mes données de modèle POSTed avec les valeurs de formulaire renseignées et ModelState est également perdu. Le modèle dans viewdata devenait également nul.
Enfin, j'ai essayé de mettre à jour les données de modèle sous forme Postée à l'aide de la méthode TryUppdateModel, qui prend l'instance de modèle et le préfixe html passés précédemment à la vue partielle.
S'il vous plaît laissez-moi savoir si cette approche est bonne ou peu diversifiée!
Vous pouvez essayer de passer le ViewModel au partiel.
@model my.path.to.namespace.MyViewModel
@Html.TextBoxFor(m => m.ComplexModel.Name)
Modifier
Vous pouvez créer un modèle de base et y insérer le modèle complexe et transmettre le modèle de base au modèle partiel.
public class MyViewModel :BaseModel
{
public string SomeProperty { get; set; }
}
public class MyViewModel2 :BaseModel
{
public string SomeProperty2 { get; set; }
}
public class BaseModel
{
public MyComplexModel ComplexModel { get; set; }
}
public class MyComplexModel
{
public int id { get; set; }
public string Name { get; set; }
...
}
Ensuite, votre partiel sera comme ci-dessous:
@model my.path.to.namespace.BaseModel
@Html.TextBoxFor(m => m.ComplexModel.Name)
Si ce n'est pas une solution acceptable, vous devrez peut-être penser à remplacer le classeur. Vous pouvez lire à ce sujet ici .