fizch
fizch

Reputation: 2609

MVC form data loss after validation

Ok, let me start out by saying that I am brand new to MVC. With that out of the way, I am using the version of MVC that ship with Visual Studio 2010. This is also using Visual Basic, but I am sure that you can figure that out once you see the code.

I am trying to validate my data, and the validation process is working correctly. However, if the validation fails the values that were in my textbox are not reloaded on the form.

My form is fairly simplistic as I wanted to start with something simple for my first application. It consists of a table that is tied to a collection of Agreement objects. At the bottom of the table, I have two textboxes for adding a new agreement. It is these two textboxes that are not getting the data posted back to them.

Here is the view:

<%@ Page Title="" Language="VB" MasterPageFile="~/Views/Shared/Food.Master" Inherits="System.Web.Mvc.ViewPage(Of IEnumerable (Of NdaToolLibrary.BusinessLayer.Agreement))" %>

<asp:Content ID="Content1" ContentPlaceHolderID="PrimaryContent" runat="server">

<h1>Agreement List</h1>

<table cellpadding="0" cellspacing="0" border="0" class="tableDefault" style="width: 300px !important">
    <tr>
        <th>
            AccountType
        </th>
        <th>
            NationalId
        </th>
        <th></th>
    </tr>

<% For i As Integer = 0 To Model.Count - 1%>

    <tr class="<%= IIF(i mod 2 = 0, "", "detailRow") %>">
        <td>
            <%: Model(i).AccountType%>
        </td>
        <td>
            <%: Model(i).NationalId%>
        </td>
        <td>
            <%: Html.RouteLink("Delete", "Delete", New With {.action="Delete", .acctType = Model(i).AccountType, .id = Model(i).NationalId})%>
        </td>
    </tr>

<% Next%>

    <tr class="footerRow">
        <td>
            <%= Html.TextBox("AccountType")%>
            <%= Html.ValidationMessage("AccountType", " ")%>
        </td>
        <td>
            <%= Html.TextBox("NationalId")%>
            <%= Html.ValidationMessage("NationalId"," ")%>
        </td>
        <td>
            <a href="javascript: document.forms[0].action='/Agreement/Create'; document.forms[0].submit();">Create</a>
        </td>
    </tr>
</table>

<%= Html.ValidationSummary("Could not save agreement. Reasons include:", New with{.class = "red"})%>
</asp:Content>

Here is the controller:

Namespace Web
Public Class AgreementController
    Inherits System.Web.Mvc.Controller

    Public Function Create(ByVal FormValues As FormCollection) As ActionResult
        Dim agreement As New BusinessLayer.Agreement()

        agreement.AccountType = FormValues("AccountType").ToString()
        agreement.NationalId = FormValues("NationalId").ToString()

        If agreement.IsValid Then
            Try
                agreement.Save()
            Catch ex As Exception
                ModelState.AddModelError("", ex.Message)
            End Try
        Else
            For Each validationError As BusinessLayer.DataValidationMessage In agreement.GetValidationResults()
                ModelState.AddModelError(validationError.Property, validationError.Message)
            Next
        End If

        'Try
        '    agreement.AccountType = FormValues("AccountType").ToString()
        '    agreement.NationalId = FormValues("NationalId").ToString()

        '    agreement.Save()
        'Catch dvEx As BusinessLayer.DataValidationException
        '    For Each validationError As BusinessLayer.DataValidationMessage In dvEx.ValidationMessages
        '        ModelState.AddModelError(validationError.Property, validationError.Message)
        '    Next
        'Catch ex As Exception
        '    ModelState.AddModelError("", ex.Message)
        'End Try

        Dim agreements As New BusinessLayer.AgreementCollection()
        agreements.Load()

        Return View("Index", agreements)
    End Function

    Public Function Delete(ByVal AcctType As String, ByVal Id As String) As ActionResult
        Dim agreement As New BusinessLayer.Agreement()
        agreement.AccountType = AcctType
        agreement.NationalId = Id

        Return View("Delete", agreement)
    End Function

    <AcceptVerbs(HttpVerbs.Post)> _
    Public Function Delete(ByVal AcctType As String, ByVal Id As String, ByVal FormValues As FormCollection) As ActionResult
        Dim agreement As New BusinessLayer.Agreement(AcctType, Id)
        agreement.Delete()

        Return RedirectToAction("Index")
    End Function

    Public Function Index() As ActionResult
        Dim agreements As New BusinessLayer.AgreementCollection()
        agreements.Load()

        ' Return View("Index", agreements) is implied because the view has the same name as the action
        Return View(agreements)
    End Function



End Class
End Namespace

Upvotes: 1

Views: 1773

Answers (1)

Claudiu
Claudiu

Reputation: 227

First of all I think you should extract your fields need to create a new account in a separate view ( right now it's in the master page). You can access this new view by putting a link to it on the master page view. Your new View should be strongly typed ( you need to create a model for it). And put the fields needed to create your account in a using (Html.BeginForm()) {} statement in your new view page.
And on the controller you must have something like

public void Create(YourModelType model)
{
     if (!ModelState.IsValid) //this will check if there are validation errors after  binding 
     {
        return View(model); //this will repopulate back the input collected from the form
     }
     //here you can put your code to process the creation 
}

Sorry to give you example in C# but I don't know VB .

Hope that my answer help you.

Upvotes: 3

Related Questions