2011-03-25 2 views
11

J'ai 1 zone de texte utilisant TextBoxFor qui contient les données.Le modèle Razor MVC perd des données sur l'action Save

J'ai un ID pour le modèle et quelques autres données de base, mais affichés comme étiquettes directement dans la vue.

Lorsque je soumets le formulaire, seul le champ de zone de texte contient des données sur le modèle, tout le reste est nul, y compris l'ID. Cela signifie qu'il ne sera pas enregistré dans la base de données.

Qu'est-ce qui entraînerait l'annulation de tous les champs en dehors de la zone de texte?

+0

Publiez votre code s'il vous plaît. –

+1

Veuillez poster le code * minimal * (c'est-à-dire pas toute la demande) qui illustre le problème. Incluez votre code d'affichage ainsi que les méthodes d'action pertinentes. – marcind

+0

@Bugai, je sais son difficile de diagnostiquer le problème sans code, mais son code de publication vraiment très difficile quand vous avez de gros morceaux de code à travers 1) la vue, 2) le contrôleur, 3) le modèle et tous contiennent le contexte qui est sans rapport avec le problème. – jaffa

Répondre

16

Ceci est la façon dont le web fonctionne, ne forment que des éléments sont soumis à la forme et les étiquettes ne sont pas former des éléments.

Qu'est-ce qui se passe ici est communément admis que vous:

  1. Render un champ caché (Html.Hidden/Html.HiddenFor) contenant le Id ainsi que les zones de texte
  2. Accepter les changements dans votre action de commande (en tant que paramètres ou un objet)
  3. hydrater l'instance de l'objet représenté par Id de votre dépôt/base de données
  4. Appliquer les modifications à l'instance hydratée
  5. Valider l'état de l'objet et mettre à jour votre dépôt/base de données (ou tout ce que vous aviez l'intention de faire avec elle)

Comme la classe de données affiché est souvent « invalide » en raison de ses propriétés manquantes (ceux marqués comme [Required] par exemple), il est très courant de créer une nouvelle classe dont seules les propriétés sont modifiées (appelée "modèle de commande"). Cette classe peut avoir ses propres propriétés de validation et ainsi ne pas dégringoler avec la validation de votre formulaire.

+0

Excellent, merci pour la réponse claire et concise. Cela rend beaucoup plus clair, il y a beaucoup de travail à faire de ma part pour enlever la mentalité de webform de mon cerveau! – jaffa

6

Seules les entrées sont renvoyées au serveur. Si vous voulez que le modèle soit basé sur les données de la page, il doit s'agir d'entrées (ou d'une partie de l'URL). Les données des éléments d'étiquette ne seront pas publiées sur le serveur avec le formulaire (comportement de formulaire HTML standard). Généralement, vous utiliseriez des champs masqués pour publier des données de modèle non modifiables ou simplement référencer l'ID de modèle et repeupler à partir de la base de données, en mettant à jour les propriétés modifiables (comme ci-dessous).

Exemple:

@(using Html.BeginForm(new { id = Model.ID })) 
{ 
     <p> 
      <label>Fixed Property:</label> 
      @Model.SomeFixedProperty 
     </p> 
     <p> 
      @Html.LabelFor(m => m.EditableProperty) 
      @Html.TextBoxFor(m => m.EditableProperty) 
     </p> 
} 

Contrôleur

[HttpPost] 
public ActionResult Foo(int id, string editableProperty) 
{ 
    var model = repo.GetById(id); 
    model.EditableProperty = editableProperty; 
    repo.Save(); 
    return View(model); 
} 
+0

Ok, mais que faire si vous avez un formulaire complet qui affiche 10 étiquettes, et 1 étiquette pour l'édition. Comment suis-je censé ramener ces données au modèle sans que tout soit réinitialisé? Cela ressemble à un problème majeur que ViewState aurait résolu? – jaffa

+1

@Jon - (1) les champs cachés pour accompagner l'étiquette pour chaque chose dont vous avez besoin repopulated dans le modèle, (2) utiliser TempData pour conserver les données de la demande précédente, ou (3) inclure suffisamment d'informations pour reformuler les données nécessaires . ViewState fait réellement (1), bien que les données soient cryptées. Vous pouvez, si vous le souhaitez, répliquer cette fonctionnalité mais je ne la recommanderais pas. De ce que vous dites, je choisirais probablement (3) et inclurais l'id de modèle dans l'url. Demandez à votre contrôleur de prendre l'identifiant et les données mises à jour en tant que paramètres. Récupérer le modèle à partir de la base de données et modifier seulement wnat nécessaire. – tvanfosson

+0

@Jon - Veuillez regarder dans l'état de la session et comprendre comment elle évolue avant de s'appuyer sur 'TempData', car c'est ce que' TempData' encapsule. –

0

Bien que je sois d'accord avec @RichardSzalay, un autre moyen serait de marquer les propriétés inchangées comme non modifiées. Supposons que vous ayez un modèle avec les propriétés suivantes: Id, Nom, E-mail. Et vous ne voulez pas changer de courriel. L'inconvénient est que vous pouvez rencontrer des problèmes de validation à cause des champs manquants dans le modèle.