2009-11-24 12 views
1

Je tente de générer une vue générée dynamiquement. Ma classe de contrôleur pour créer l'action se présente comme suitRendu ASP.NET MVC Afficher et conserver les valeurs lorsque la validation échoue sur une vue générée dynamiquement

public ActionResult Create() 
{ 
     List<FormMetadata> formItems = GetFormItems(); 

     return View(formItems); 
} 

et la vue à ce jour est quelque chose comme ça

<% using (Html.BeginForm()) 
    {%> 
<table> 
    <% foreach (var item in Model) 
     { 
      if (!item.IsActive) 
      { 
       continue; 
      } 
    %> 
    <tr> 
     <td> 
      <%=Html.Encode(item.DisplayValue)%> 
     </td> 
     <td> 
      <% 
       if (item.FieldType == "TextBox") 
       {%> 
      <%=Html.TextBox(item.Field, null, new { tabindex = item.SortOrder })%> 
      <%} 
       if (item.FieldType == "CheckBox") 
       {%> 
      <%=Html.CheckBox(item.Field, false, new { tabindex = item.SortOrder })%> 
      <%} 

      %> 
     </td> 
     <td> 
     </td> 
    </tr> 
    <%} %> 
</table> 

Je veux montrer la même vue avec les valeurs retenues quand il y a des erreurs de validation. Code comme le suivant est utilisé pour attraper les erreurs de validation

if (string.IsNullOrEmpty(collection[item.ToString()])) 
{ 
     ModelState.AddModelError(key, "Required."); 
} 

Comment puis-je afficher une vue avec des erreurs de validation, tout en conservant les valeurs qui ont été saisies pour ce scénario?

+0

Pouvez-vous expliquer le scénario sous lequel cela devient utile. On dirait que vous essayez de faire une sorte de système EAV. – Neal

Répondre

0

EDIT2

J'ai créé un projet rapide de l'échantillon qui fonctionne. Il y a une chose que je n'aime pas, c'est que je ne peux pas passer la liste elle-même. Je dois créer la liste vide à chaque fois et lire toutes les valeurs des zones de texte et les enregistrer dans la liste et donner cette liste mise à jour à la nouvelle vue. Prochain tour même chose. Mais ça fonctionne.

En gros:

public ActionResult About() { 
     List<FormMetaData> formItems = GetFormItems(); 

     return View(formItems); 
    } 

    [AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult About(FormCollection form) 
    { 
     List<FormMetaData> formItems = GetFormItems(); 
     //TryUpdateModel(formItems); 


     // update project members  
     foreach (var key in form.AllKeys) { 
      if (key.ToString().StartsWith("TextBox")) { 
       string field = (key.ToString().Replace("TextBox", "")); 
       if (!string.IsNullOrEmpty(form.Get(key.ToString()))) { 
        formItems.Find(delegate(FormMetaData t) { return t.Field == field; }).Value = form.Get(key.ToString()); 
       } 
       else { } 
        // this.ProjectRepository.DeleteMemberFromProject(id, userId); 
      } 
     } 

     ModelState.AddModelError("test", "this is a test error"); 
     if(ModelState.IsValid) 
     { 
       /// 
     } 
     else 
     { 
      return View(formItems); 
     } 
     return View(formItems); 
    } 

    private List<FormMetaData> GetFormItems() { 
      List<FormMetaData> output = new List<FormMetaData>(); 

      FormMetaData temp1 = new FormMetaData("TextBox",true,"temp1","displayText1"); 
      FormMetaData temp2 = new FormMetaData("TextBox", true, "temp2", "displayText2"); 
      output.Add(temp1); 
      output.Add(temp2); 

      return output; 
     } 

et vous avez votre point de vue:

<% using (Html.BeginForm()) {%> 
<table> 
    <% foreach (var item in Model) { 
      if (!item.isActive) { 
       continue; 
      } %> 
    <tr> 
     <td> 
      <%=Html.Encode(item.DisplayValue)%> 
     </td> 
     <td> 
      <% if (item.FieldType == "TextBox") {%> 
      <%=Html.TextBox("TextBox"+item.Field, item.Value)%> 
      <%} if (item.FieldType == "CheckBox") {%> 
      <%=Html.CheckBox("Value")%> 
      <%}%> 
     </td> 
     <td> 
     </td> 
    </tr> 
    <%} %> 
    <p> 
      <input type="submit" value="submit" /> 
     </p> 
     <% } %> 
</table> 

J'ai téléchargé un fichier zip pour vous @http://www.bastijn.nl/zooi/dynamicSample.rar

EDIT

J'ai essayé cet exemple et ça va w Rong avec le modelbinder. Lorsque j'utilise "FormCollection form" comme entrée dans la méthode POST create, les valeurs de mes zones de texte sont présentes sous la clé fournie. Donc, vous devez soit votre classeur modèle personnalisé ou faire un modèle qui fonctionnera avec le classeur modèle par défaut.

Pour être plus précis. Cela ne fonctionne pas car, dans ce cas, vos zones de texte mettent à jour les propriétés des objets à l'intérieur de la liste , qui correspond au modèle Model transmis. Normalement, vos zones de texte mettent à jour les propriétés à l'intérieur du objet qui est également votre modèle et la clé utilisée pour la zone de texte (pour le maquettage automatique) est le nom de la propriété que vous mettez à jour.

Je suppose donc que le classeur modèle ne lie pas les valeurs de la zone de texte à vos éléments de la liste, car il ne sait tout simplement pas comment procéder automatiquement. Il est 3 h 17 ici, alors je vais me coucher, la question est intéressante et je pourrais terminer la réponse demain.

originale

<%=Html.TextBox(item.Field, null, new { tabindex = item.SortOrder })%> 

Il semble que vous générez votre formulaire chaque fois avec les valeurs définies à null.

Essayez de les initialiser quelque chose comme:

<%=Html.TextBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%> 

Et dans votre contrôleur, lorsque vous vérifiez pour ModelState.IsValid faire quelque chose comme:

if(ModelState.isValid){ 
    //code when it works 
} 
else{ 
    return View(formItems) // these should contain the just added values 
} 

Cela devrait faire l'affaire.

Ainsi, dans un exemple simple, vous obtenez quelque chose comme:

public ActionResult Create() 
{ 
    List<FormMetadata> formItems = GetFormItems(); 

    return View(formItems); 
} 

[AcceptVerbs(HttpVerbs.Post)] 
public ActionResult Create(List<FormMetadata> formItems) 
{ 
    if(ModelState.isValid) 
    { 
     MyUpdate() 
     save() 
    } 
    else 
    { 
     return view(formItems) 
    } 
} 

Et votre point de vue:

<% 
    if (item.FieldType == "TextBox") 
    {%> 
     <%=Html.TextBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%> 
     <%} 
      if (item.FieldType == "CheckBox") 
      {%> 
       <%=Html.CheckBox(item.Field, **item.Value**, new { tabindex = item.SortOrder })%> 
      <%} 
+0

J'ai essayé cette approche. Les objets formItems de l'action HttpVerbs.Post Create envoient toujours une valeur nulle dans le contrôleur. – chrisk

+0

C'est probablement parce que modelbinder par défaut essayera de lier la valeur dans la zone de texte à votre clé (première valeur). Donc, en fait, il doit être quelque chose comme: <% = Html.TextBox ("item.Value", item.Value, nouveau {tabindex = item.SortOrder})%> Maintenant, il essaie de lier la valeur trouvée dans le textbox à votre Model.item.Value. Bien sûr, vous pouvez nommer comme vous le souhaitez. – bastijn

+0

a édité cette réponse avec une épingle sur le problème (comme je le soupçonne). – bastijn

0

Je serais à la vérification NerdDinner d'abord et essentiellement en utilisant la même approche.

0

J'utilise la maintenant approche suivante, ne travaillant qu'avec des zones de texte au moment

La vue a

<% 
for (int i = 0; i < Model.Count; i++) 
{ 
    var name = "formItems[" + i + "].Field"; 


    var htmlAttributes = new Dictionary<string, object> 
          { 
           {"tabindex", Model[i].SortOrder}, 
           {"class", Model[i].ClientSideValidation} 
          }; 


%> 
    <div> <%=Html.Encode(Model[i].DisplayValue)%> 
    <%=Html.TextBox(name, Model[i].DefaultValue, htmlAttributes)%> 
    <%= Html.ValidationMessage(Model[i].Field) %> 
    </div> 

<% } %> 

et le contrôleur des méthodes d'action GET

public ActionResult Create() 
{ 
    List<FormMetadata> formItems = GetFormItems(); 

    HttpContext.Cache[FormCacheKey] = formItems; 

    return View(formItems); 
} 

POST (partie du code)

[AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult Create(List<FormMetadata> formItems) 
    { 
     var formDefinition = new List<FormMetadata>(); 

     try 
     { 
      if (HttpContext.Cache[FormCacheKey] != null) 
      { 
       formDefinition = HttpContext.Cache[FormCacheKey] as List<FormMetadata>; 
      } 
      else 
      { 
       formDefinition = GetFormItems(); 
       HttpContext.Cache[FormCacheKey] = formItems; 
      } 

      var formValues = new Dictionary<string, string>(); 

      for (int i = 0; i < formDefinition.Count; i++) 
      { 
       var key = formDefinition[i].Field; 

       var value = formItems[i].Field ?? string.Empty;