3

I have a web app with several pages that functions as a data administration console. You can lookup data against our DB, create new entities, edit, delete, etc. It is created in ASP.NET MVC 3 with Razor.

I'm having trouble with my form post data being "lost" (not applied) between visits to the same view.

Background

The site structure is fairly typical with several views -- one for home, then one for each of the different entities (let's call them Parent, Child)

  • The Home view as a search field were you can search for Parent elements. When you submit the search, the parent entities that match are shown in an HTML table.

enter image description here

  • In the HTML table, there is actions next to each Parent row, to edit it, or show the children. If you click on Show Children, it does another form post to show the children for that parent row. E.g:

enter image description here

At first, I tried using multiple forms on the Home view: one for search, one for the each of the rows in the parent table, and one for each row in the children table. However, this caused problems with caching -- when I chose to edit one of the rows (going to the corresponding view to do that), when I got sent back to the Home view, the previous search wasn't still applied so I had to restart my search. I found that if I kept a single form for the entire page, caching worked properly, so as I dived in and out editing entities caching seemed to work (and improved overall usability).

So the code I have is roughly the following (I've edited it a lot to simplify it for this question):

@using (Html.BeginForm("Index", "Home", FormMethod.Post ))
{
  <div>
    @Html.TextBoxFor(m => m.SearchTerm )
    <input type="submit" name="SearchSubmit" value="Search" />
  </div>
  <h2>Parents</h2>
  <div>
    @{
      var parents = Tool.Models.ToolsModelService.SearchParents(Model.SearchTerm);
    }
  </div>
  <div>
    <table>
        <thead>
           <tr>
             <th>Parent ID</th>
             <th>Attribute 1</th>
             <th>Attribute 2</th>
             <th>Actions</th>
           </tr>
        </thead>
        <tbody>
          @foreach (var p in parents)
          {
            <tr>
               <td>@p.ID</td>
               <td>@p.Name</td>
               <td>@p.Attrib1</td>
               <td>@p.Attrib2</td>
               <td>
                 <input type="hidden" name="SelectedParent" value="@p.ID.ToString()" />
                 <input type="submit" name="ParentSubmit" value="Edit" />
                 <input type="submit" name="ChildrenSubmit" value="Show Children" />
               </td>
            </tr>
           }
        </tbody>
     </table>
  </div>
  <div>
    <button type="submit" name="ParentSubmit" value="Add">Add New Parent</button>
  </div>
  @if (Model.SelectedParent != null)
  {
    var children = Tool.Models.ToolModelService.GetChildren(Model.SelectedParent);
    if (children != null && children.Count > 0)
    {
      <h2>Children</h2>
      <div>
        <table>
          <thead>
            <tr>
              <th>Child ID</th>
              <th>Name</th>
              <th>Action</th>
             </tr>
           </thead>
           <tbody>
           @foreach (var c in children)
           {
             <tr>
               <td>@c.ID</td>
               <td>@c.Name</td>
               <td>
               @using (Html.BeginForm("Index", "Home", FormMethod.Post))
               {
                  <input type="hidden" name="SelectedChild" value="@c.ID.ToString()" />
                  <input type="submit" name="ChildrenSubmit" value="Edit" />
               }
               </td>    
             </tr>
           }
           </tbody>
         </table>
       </div>
       <div>
         <input type="submit" name="MenuItemSubmit" value="Add">Add new child</button>
       </div>
    }
  }
  else
  {
    <h2>Children</h2>
    <div>
      <p>Select a parent to show children for<p>
    </div>
  }

In the HomeController.cs, there is a bunch of code. Here is some of the form handling:

...

[Authorize]
public ActionResult Index(HomeModel model)
{
    model = new HomeModel();
    this.LoadState(model);
    return View(model);
}

[ActionName("Index")]
[AcceptVerbs(HttpVerbs.Post)]
[AcceptParameter(Name = "SearchSubmit", Value = "Search")]
public ActionResult Register_Search(HomeModel model)
{
    ActionResult action;
    this.CacheState(model);
    action = this.View(model);
    return action;
}

[ActionName("Index")]
[AcceptVerbs(HttpVerbs.Post)]
[AcceptParameter(Name = "ParentSubmit", Value = "Add")]
public ActionResult Register_ParentAdd(HomeModel model)
{
    this.CacheState(model);
    return this.RedirectToAction("Index", "Parent");
}

...

private void CacheState(HomeModel model)
{
    this.Session[CachedModelKey] = model;
}

private void LoadState(HomeModel model)
{
   if (null != this.Session[CachedModelKey])
   {
       var cachedModel = (HomeModel)this.Session[CachedModelKey];
       model.SearchTerm = cachedModel.SearchTerm;
       model.SelectedRestaurant = cachedModel.SelectedParent;
       model.SelectedMenuItem = cachedModel.SelectedChild;
   }
}

Problems

I'm having various problems, and I'm positive it's due to me being very new to ASP.NET MVC and how to properly set everything up in my code.

  1. The parents table form doesn't work correctly. If I click on Show children for anything row, it always shows the children for the first row.

  2. If I search for Parent1, chose it's children, then edit one of the child items (which is on a separate view). I eventually get sent back to the Home view, but the search is no longer applied -- this is what I mean by "caching"; my form post values aren't being persisted across reloads of the view in all cases.

I have to search again for parent1 which slows the workflow down. I really want to persist the searches so I don't have re-search to bring up the same child list (makes it simpler to keep editing multiple children for same parent)

I'm sure I'm missing something here really straightforward, so would appreciate some help that would solve the above problems, but also any advice on better ways to structure things. If I'm missing any info, let me know and I'll add it.

4

1 回答 1

1

处理此类页面的一个好方法是使用Backbone.js 在 Backbone 中,您可以设置绑定到 html 模板的客户端视图。您将模型数据加载到模板中,然后渲染视图。

您可以在主干视图中连接事件,这些事件可以监听主干模型上的更改,然后渲染显示更改的适当视图。

Backbone 有一个学习曲线,但如果你从一个预先构建的示例开始,你就会掌握它的窍门。绝对值得学习,因为它非常适合您的页面。

Rob Conery 在这里做了一个很好的例子...... http://wekeroad.com/2011/08/11/the-backbonejs-todo-list-sample-refactored-part-1/

缓存明智我会让您的视图模型对象可序列化,然后使用 System.Runtime.Caching.MemoryCache 针对从您的搜索参数构造的键缓存对象。这将避免不必要的数据库访问。

于 2012-09-08T11:48:49.003 回答