2013-05-15 11 views
7

Es ist schwer für mich, das Problem, das ich habe, klar zu definieren. Ich versuche zu verstehen, wie Werte in Formularfeldern beibehalten werden, die nach einer fehlgeschlagenen Validierung in einer Schleife erstellt werden. Ich habe eine kompliziertere reale Welt Form, die eine Reihe von Elementen in der Schleife und Validierung erstellt hat. Ich habe es auf ein einfaches Beispiel unten reduziert.

Wenn die Validierung fehlschlägt, möchte ich die Textfelder mit dem Namen "Kommentar", die in der Schleife erstellt wurden, um die Werte beizubehalten, die unten im Bild Pre-Submit angezeigt werden.

Wenn ich die Formularübergabe debuggen, werden die Werte aus den einzelnen Feldern erfolgreich mit der IList-Variablen namens Comment im Modell verbunden. Dies ist, was ich will, also kann ich sie durchlaufen und sie auf Index basierend lokalisieren.

Nach dem Senden zeigt jedes von der Schleife erzeugte Textarea die kommagetrennte Darstellung der IList-Variablen Kommentar im Modell. Es scheint, dass das Feld in der Ansicht und im Modell eine Verbindung herstellt, da sie einen Namen teilen. Sie verbinden sich richtig auf dem Weg hinein, aber nicht auf dem Weg nach draußen. Ich möchte, dass in der Ansicht nur der Wert angezeigt wird, der mit dem Kommentar [i] anstelle der gesamten Liste verknüpft ist, sodass die Werte zwischen den Formularübergaben konstant bleiben.

Screenshots und Beispielcode unten
Erste Last:
First load of form without changes

Pre-Formular senden Änderungen:
Form with changes to the first input before submitting

Formular gesehen nach dem ersten einreichen:
Form as seen after the first submission

Formular als nach der zweiten gesehen einreichen:
enter image description here

Model Code
HTML.Textarea Werte in MVC Razor View

using System.Collections.Generic; 
namespace UI.Models.Forms 
{ 
    public class TempListModel : ContentModel 
    { 
     public TempListModel() 
     { 
      Comment = new List<string>(); 
     } 
     public IList<string> Comment { get; set; } //Comments for each URL in the list 
    } 
} 


Code anzeigen

@model UI.Models.Forms.TempListModel 
@using (Html.BeginForm("temptest", "Test", new { id = 1 }, FormMethod.Post, new { id = "listForm", name = "listForm" })) 
{ 
    <ul> 
     @for (int i = 0; i < Model.Comment.Count(); i++) 
     { 
      <li> 
       <div class="llformlabel"> 
        Notes: 
        <div>@Model.Comment[i]</div> 
        @Html.TextArea("Comment", Model.Comment[i], 4, 63, new { @id = "Comment_" + i, @title = "Comment" })</div> 
      </li> 
     } 
    </ul> 
    <input type="submit" value="Save Changes" /> 
} 


-Controller-Code

using System.Collections.Generic; 
using System.Web.Mvc; 
using UI.Models.Forms; 
namespace UI.Controllers 
{ 
    public class TestController : Controller 
    { 
     [AcceptVerbs(HttpVerbs.Post)] 
     public ActionResult TempTest(TempListModel model) 
     { 
      //This function executes after the user submits the form. 
      //If server side validation fails then the user should be shown the form as it was when they submitted. 
      //model.Comment = GetComments(); //In my real world example this comes from a database. 
      if (true) //!ModelState.IsValid) //In my real world code this is a validation step that may fail 
      { 
       return View(model); 
      } 
     } 
     [AcceptVerbs(HttpVerbs.Get)] 
     public ActionResult TempTest(int? id) 
     { 
      //In the real world example there is a lot going on in this function. 
      //It is used to load data from databases and set up the model to be displayed. 
      var model = new TempListModel(); 
      model.Comment = GetComments(); 
      return View("TempTest", "TempLayout", model); 
     } 
     private static IList<string> GetComments() 
     { 
      //Simple sample function used for demo purposes. 
      IList<string> comments = new List<string>(); 
      comments.Add("Comment 1"); 
      comments.Add("Comment 2"); 
      comments.Add("Comment 3"); 
      return comments; 
     } 
    } 
} 

Antwort

8

Wenn Sie die Validierung nicht nur das Modell zurück.

[AcceptVerbs(HttpVerbs.Post)] 
    public ActionResult TempTest(TempListModel model) 
    { 
     if (ModelState.IsValid) 
     { 
      return RedirectToAction("TempTest"); 
     } 
     return View(model); 
    } 

bearbeiten dies Ihrer Ansicht nach Versuchen Sie stattdessen

@for (int i = 0; i < Model.Comment.Count(); i++) 
{ 
    <li> 
     @Html.TextAreaFor(m => m.Comment[i], 4, 63, new { @title = "Comment" }) 
    </li> 
} 

Und lassen Sie die Helfer für Sie die Elemente nennen. Sie enden mit name Attribute wie Comment[i].

+0

ich geändert nur mein Codebeispiel verwendet die Ansicht statt RedirectToAction zu machen, damit es klar war, dass die GetComments Funktion der Werte war nicht zu überschreiben. Ich glaube, mein aktuelles Codebeispiel zeigt, wie Sie vorschlagen, und hat immer noch das gleiche Problem. – RacerNerd

+0

@RacerNerd siehe bearbeiten. – Jasen

+0

Danke. Das hat den Trick gemacht. Ist es angemessener, den HTML-Generator mit "For" zu verwenden, wenn ich dieses HTML-Feld immer mit einer Variablen im Modell verbinden möchte? Der Code, mit dem ich arbeite, scheint Verbindungsvariablen zu sein, wird meistens durch Namensabgleich erreicht, was, wie ich hier sehe, nicht in allen Fällen zu funktionieren scheint. – RacerNerd

2

ASP.NET MVC default ModelBinder sucht in der Anforderung nach HTML-Namen, die mit den TempListModel-Eigenschaften übereinstimmen, um das Modell auf dem Server zu erstellen. Aber Sie sind das Überschreiben der Kommentar-ID jedes HTML-Element:

@Html.TextArea("Comment", Model.Comment[i], 4, 63, new { @id = "Comment_" + i, @title = "Comment" }) 

Wenn Sie diese kundenspezifische ID zu platzieren, müssen Sie eine neue ModelBinder erstellen. Sie können die Dinge einfach so:

@Html.TextAreaFor(m => m.Comment[i], 4, 63, new { @title = "Comment" }) 

hofft, seine Hilfe, die Sie!

+1

Hallo Fals. Danke, dass du dir das angeschaut hast. Jasen hat dich dazu gebracht, aber ich schätze die zusätzliche Erklärung, um mein Verständnis zu verbessern. – RacerNerd