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.
- 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:
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.
The
parents
table form doesn't work correctly. If I click onShow children
for anything row, it always shows the children for the first row.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.