Our main site includes a Buy page that allows our customers to purchase activation keys for the Windows Desktop applications they've downloaded from our site. This Buy page was originally fragmented in design that is there were more than one forms on the view page. These were causing a headache with keeping the data on the different forms persisting when interacting on the other forms. A friend of mine gave me advice that I should make these separate forms into one form and use different actions in my controller for the page to handle the various control inputs like button clicks, etc. It turned out to be great advice. This page now works great with none of the strange quirks that I had spent quite a bit of time trying to eliminate.
I have included the source code from my view page here to show how the view is implemented. The controller code is much like any controller code for a view and is not included in this post, but should anyone have any questions about that feel free to contact me. Here is a snippet from one of the controller actions though that show how this action is decorated to make the view work with the controller action.
... [HttpPost] [ValidateAntiForgeryToken] [MultipleButton(Name = "action", Argument = "BuySearch")] public ActionResult BuySearch([Bind(Include = "ID,Price")] tblPRESSInventory tblPRESSInventory, string sortOrder, string currentFilter, string searchString, string clearSearch, int? page, string currentEmail, string customerID, int productID = 1) { ViewBag.CurrentSort = sortOrder; ViewBag.ProductID = productID; ViewBag.CurrentProductID = productID.ToString(); ViewBag.CustomerID = customerID; bool alreadyPaid = false; var tempProduct = db2.tblPRESSInventories.Find(productID); ... return View(items.ToPagedList(pageNumber, pageSize)); } ...
Also needed to make the MultipleButton decoration work is this class definition.
... [AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)] public class MultipleButtonAttribute : ActionNameSelectorAttribute { public string Name { get; set; } public string Argument { get; set; } public override bool IsValidName(ControllerContext controllerContext, string actionName, MethodInfo methodInfo) { var isValidName = false; var keyValue = string.Format("{0}:{1}", Name, Argument); var value = controllerContext.Controller.ValueProvider.GetValue(keyValue); if (value != null) { controllerContext.Controller.ControllerContext.RouteData.Values[Name] = Argument; isValidName = true; } return isValidName; } } ...
Here's the view code, note that this is used as a partial view in a couple of other views so that code does not have to duplicate the page. Those views correspond to the actions like the example above the BuySearch action. Anyway here's the complete view code. Note that the file extension was changed to add a .txt to end of filename so that you can download this file. Not sure how to grant permission for you to download the file with its correct file extension.
The last touch on the view page is the paged list pager controls displayed below the table of inventory items. This makes use of the PagedListRenderOptions to make the links in the pager control trigger post to the controller. That turned out to be fairly straightforward to implement once I knew where to look for help.
... @Html.PagedListPager(Model, page => Url.Action("Buy", new { page }), new PagedListRenderOptions { FunctionToTransformEachPageLink = (liTag, aTag) => { aTag.Attributes.Remove("href"); aTag.Attributes.Add("href", "javascript:void(0);"); aTag.Attributes.Add("onclick","updatePage('" + aTag.InnerHtml + "'," + Model.PageCount + ");"); liTag.InnerHtml = aTag.ToString(); return liTag; } }) ...
I hope this helps someone who is having similar problems in implementing a form with multiple buttons that need post event handlers.
Thanks for reading and have a blessed day!