2013-01-08 29 views
6

Mam stronę MVC4, która ma formularz z kolekcją pól wyboru, przycisków radiowych i pól tekstowych używanych jako pola wyszukiwania. Po wpisie selekcje są analizowane, a siatka o niższych wynikach jest aktualizowana o nowe wyniki. Teraz wszystkie wartości formularzy są wymazywane po powrocie, a nowe wyniki są wyświetlane w siatce - tylko siatka jest częścią modelu.Zachowanie wartości formularza po wysłaniu (nie jest częścią modelu)

Chcę, aby wszystkie selekcje formularzy zachowały swoje wartości po poście, aby użytkownik mógł zobaczyć (i zmienić) wybory do następnego wpisu/wyszukiwania. Formularz jest zsynchronizowany z widokami.

@using (Html.BeginForm("Index", "Home", FormMethod.Post, new { id = "searchform" })) 
{ 
    @Html.ValidationSummary("Please correct the following errors") 

<div style="float:left;"> 

    <div style="float:left;"> 
    <label>Name:</label> 
    @Html.TextBox("name") 
    </div> 

    <div style="float:left; margin-left:15px"> 
    <label>Company:</label> 
    @Html.TextBox("company") 
    </div> 

    <div style="float:left; margin-left:65px"> 
    <label>Date Range:</label> 
    @Html.TextBox("dateStart", "", new { @class = "datefield", type = "date" }) 
    &nbsp;to&nbsp; 
    @Html.TextBox("dateEnd", "", new { @class = "datefield", type = "date" }) 
    </div> 

</div> 

<div style="clear: both;"> 
    Match Any Categories? <input type="radio" name="categoryMatchAll" value="false" checked="checked" />&nbsp;&nbsp;&nbsp; 
    Match All Categories? <input type="radio" name="categoryMatchAll" value="true" /> 
</div> 

<div style="float:left;"> 

    <div id="searchform-categories" style="float:left;"> 
     <div class="scroll_checkboxes"> 
      <label>Categories</label> 
      <ul> 
      @foreach (var x in ViewBag.Categories) 
      { 
        <li> 
         <input type="checkbox" name="categories" value="@x.Id"/> 

         @x.Name 

        </li> 
      } 
      </ul> 
     </div> 
    </div> 

    <div id="searchform-diversity" style="float:left; margin-left:30px">  
     <div class="search-selection" style="float:left;"> 
      <label>Minority Owned</label> 
      <ul> 
       @foreach (var x in ViewBag.Minorities) 
       { 
        <li> 
         @Html.RadioButton("minorities", (String)x.Id.ToString()) 
         @x.Name 
        </li> 
       } 
      </ul> 
     </div> 
     <div class="search-selection" style="float:left;"> 
      <label>Diversity Class</label> 
      <ul> 
      @foreach (var x in ViewBag.Classifications) 
      { 
       <li> 
        @Html.RadioButton("classifications", (String)x.Id.ToString()) 
        @x.Name 
       </li> 
      } 
     </ul> 
     </div>  
    </div> 

</div>  

<div style="clear: both;"> 
    <input type="submit" value="Search Profiles" /> 
    <input type="submit" value="Reset" /> 
    </div>  
} 

siatka danych jest zobowiązany do modelu jako

@model IEnumerable<VendorProfileIntranet.Models.VendorProfile> 

<table id="VendorTable" width="100%" class="gradeA"> 
<thead> 
    <tr> 
    <th> 
     @Html.DisplayNameFor(model => model.Name) 
    </th> 
    <th> 
     @Html.DisplayNameFor(model => model.CompanyName) 
    </th> 
    <th> 
     @Html.DisplayNameFor(model => model.City) 
    </th> 
    <th> 
     @Html.DisplayNameFor(model => model.State) 
    </th> 
    <th> 
     @Html.DisplayNameFor(model => model.DateCreated) 
    </th> 
    <th>Actions</th> 
    </tr> 
</thead> 
<tbody> 

@foreach (var item in Model) 
{ 
<tr> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => item.Name) 
    </td> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => item.CompanyName) 
    </td> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => item.City) 
    </td> 
    <td> 
     @Html.DisplayFor(modelItem => item.State) 
    </td> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => item.DateCreated) 
    </td> 
    <td class="list-field"> 
     @Html.ActionLink("Edit", "Edit", new { id = item.ProfileID }) | 
     @Html.ActionLink("View", "View", new { id = item.ProfileID }) | 
     @Html.ActionLink("Delete", "Delete", new { id = item.ProfileID }, new { onclick = " return DeleteConfirm()" }) 
    </td> 
</tr> 

} 

</tbody> 
<tfoot> 
    <tr> 
     <td>&nbsp;</td> 
    </tr> 
</tfoot> 

Odpowiedz

1

Oto, jak zwykle rozwiązuję ten problem. Moje notatki są wyłącznie moją opinią (religijną?) O nazwach klas w projekcie MVC, aby jasno określić ich cel.

Para interfejsów do utrzymania go rozszerzalny:

// be specific about what type of results, both in the name of the 
// interface and the property needed, you don't want to have overlapping 
// properies on your classes, I like suffixing interfaces that are specific 
// to a View or Partial View with View 
public interface IPersonSearchResultsView 
{ 
    IEnumerable<EFPerson> PersonSearchResults { get; } 
} 

public interface IPersonSearchCriteriaView 
{ 
    PersonSearchCriteriaModel PersonSearchModel { get; } 
} 

Kilka klas

// I like suffixing classes that I only use for MVC with Model 
public PersonSearchCriteriaModel 
{ 
    public string Name {get; set;} 
    public string Company {get; set;} 
    public string DateStart {get; set;} 
    public string DateEnd {get; set;} 
} 

// I like suffixing classes that I used passed to a View/Partial View 
// with ViewModel  
public class PersonSearchViewModel : IPersonSearchResultsView, 
            IPersonSearchCriteriaView 
{ 
    public IEnumerable<EFPerson> PersonSearchResults { get; set; } 
    public PersonSearchCriteriaModel PersonSearchModel { get; set; } 
} 

Teraz dla kontrolerów, będę je ustawić w taki sposób, że będzie również pozwalają robić Ajax w przyszłości.

public PersonController : Controller 
{ 
    public ActionResult Search() 
    { 
    var model = new PersonSearchViewModel(); 
    // make sure we don't get a null reference exceptions 
    model.PersonSearchModel = new PersonSearchCriteriaModel(); 
    model.PersonSearchResults = new List<EFPerson>(); 
    return this.View(model); 
    } 

    [HttpPost] 
    public ActionResult Search(PersonSearchViewModel model) 
    { 
    model.PersonSearchResults = this.GetPersonResults(model.PersonSearchModel); 

    return this.View(model) 
    } 

    // You could use this for Ajax 
    public ActionResult Results(PersonSearchViewModel model) 
    { 
    model.PersonSearchResults = this.GetPersonResults(model.PersonSearchModel); 

    return this.Partial("Partial-SearchResults", model) 
    } 

    private GetPersonResults(PersonSearchCriteriaModel criteria) 
    { 
    return DbContext.GetPersonResults(criteria) 
    } 
} 

Utwórz kilka częściowych wyświetleń widoków.

/Views/Person/Partial-SearchCriteria.cshtml

@model IPersonSearchCriteriaView 

// the new part is for htmlAttributes, used by Ajax later 
@using (Html.BeginForm(..., new { id="searchCriteria" })) 
{ 
    // Here is were the magic is, if you use the @Html.*For(m=>) 
    // Methods, they will create names that match the model 
    // and you can back back to the same model on Get/Post 

    <label>Name:</label> 
    @Html.TextBoxFor(m => Model.PersonSearchModel.Name) 

    // or let mvc create a working label automagically 

    @Html.EditorFor(m => Model.PersonSearchModel.Name) 

    // or let mvc create the entire form.. 

    @Html.EditorFor(m => Model.PersonSearchModel) 
} 

/Views/Person/Partial-SearchResults.cshtml

@model IPersonSearchResultsView 

@foreach (var person in Model.PersonSearchResults) 
{ 
    <tr> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => person.Name) 
    </td> 

    // etc 
    </tr> 
} 

i wreszcie widok:

/Widoki/Osoba/Szukaj.cshtml

@model PersonSearchViewModel 

@Html.Partial("Partial-SearchCriteria", Model) 

// easily change the order of these 

<div id="searchResults"> 
@Html.Partial("Partial-SearchResults", Model); 
</div> 

Teraz umożliwiając Ajax jest dość szalony łatwe (uproszczony i mój nie być dokładnie prawej):

$.Ajax({ 
    url: '/Person/Results', 
    data: $('#searchCriteria').serialize(), 
    success: function(jsonResult) 
    { 
    $('#searchResults').innerHtml(jsonResult); 
    }); 
+0

thx za dostarczenie wszystkiego, spróbuję twojego rozwiązania. – SQLGrinder

1

Co ja zazwyczaj nie jest zdać zamieszczonych model z powrotem do widzenia. W ten sposób wartości nie zostaną usunięte.

Twój kod będzie wyglądał tak:

<div style="float:left;"> 

    <div style="float:left;"> 
    <label>Name:</label> 
    @Html.TextBox("name", Model.Name) 
    </div> 

<div style="float:left; margin-left:15px"> 
<label>Company:</label> 
@Html.TextBox("company", Model.Company) 
</div> 

<div style="float:left; margin-left:65px"> 
<label>Date Range:</label> 
@Html.TextBox("dateStart", Model.DateStart, new { @class = "datefield", type = "date" }) 
&nbsp;to&nbsp; 
@Html.TextBox("dateEnd", Model.DateEnd, new { @class = "datefield", type = "date" }) 
</div> 

Kiedy początkowo coraz formularz, musisz utworzyć nowy Model, w przeciwnym razie Model będzie nieważne i wyjątek, gdy właściwości nazywane są na to.

Przykładowy model

public class SearchModel 
{ 

    public SearchModel() 
    { 
     Results = new List<Result>(); 
    } 

    public string Name {get; set;} 

    public string Company {get; set;} 

    public string DateStart {get; set;} 

    public string DateEnd {get; set;} 

    public List<Result> Results {get; set;} 
} 


@foreach (var item in Model.Results) 
{ 
<tr> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => item.Name) 
    </td> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => item.CompanyName) 
    </td> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => item.City) 
    </td> 
    <td> 
     @Html.DisplayFor(modelItem => item.State) 
    </td> 
    <td class="list-field"> 
     @Html.DisplayFor(modelItem => item.DateCreated) 
    </td> 
    <td class="list-field"> 
     @Html.ActionLink("Edit", "Edit", new { id = item.ProfileID }) | 
     @Html.ActionLink("View", "View", new { id = item.ProfileID }) | 
     @Html.ActionLink("Delete", "Delete", new { id = item.ProfileID }, new { onclick = " return DeleteConfirm()" }) 
    </td> 
</tr> 

} 

Oto link na tworzeniu modeli widoku w MVC.

+0

Rozumiem, że możesz mieć tylko jeden model, który jest już zajęty przez siatkę danych, więc nie jestem pewien, jak włączyć to, co sugerujesz. (patrz zaktualizowane powyżej) – SQLGrinder

+0

@Vic Tak, to prawda, ale Model to po prostu klasa. Możesz mieć wszystko w klasie. –

+0

@Vic na GET, Wyniki będą puste - nie wyświetlają się żadne wiersze. Po zakończeniu wyszukiwania wyświetlane są wyniki i kryteria wyszukiwania. –

1

jeśli używasz html w MVC następnie sprawdzić Rozwiązanie 2 z here, value="@Request["txtNumber1"]" działało w porządku dla mnie,

<input type="text" id="txtNumber1" name="txtNumber1" value="@Request["txtNumber1"]"/> 

nadzieja pomaga komuś.

+0

Dlaczego w dół głosowanie? proszę wyjaśnić, aby dodać lepszą odpowiedź w przyszłości. – stom

Powiązane problemy