web-dev-qa-db-fra.com

obtenir les valeurs d'un objet complexe imbriqué qui est passé à une vue partielle

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?

23
Blair Holmes

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")
36
user3559349

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! 

0
Sachin Chauhan

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 .

0
Yogiraj