This recipe is going to be a slight twist on the previous one. Rather than force-feeding our details into the top of our page using a partial view, we will instead display the details in a modal pop-up using JSON and a jQuery plug-in called nyroModal
. You will find that two things occur with this method, which are a bit different from our last task. First, the time it takes to display the details after clicking on them is considerably less, as the package of data that is passed is much smaller. Also, there is less processing to be performed on the server-side as the formatting of the data occurs on the client-side, which also adds to the improved performance. Second, the user experience is greatly improved as the list of product data doesn't get pushed and pulled all over the place, this is because the details are cleared from and displayed in the page.
As with the other recipes in this chapter, we need to have some data to work with in order to be able to implement this recipe. We will be using our Product
and ProductRepository
classes as well as NBuilder. In addition to this, we will also be using the nyroModal
jQuery plug-in, which can be downloaded from http://nyromodal.googlecode.com/files/nyroModal-1.6.2.zip (I am using 1.6.2 in this recipe).
Product
and ProductRepository
classes from the previous recipe. nyroModal javascript
file to our Scripts
directory. Also, we have to add the nyroModal.css
file to our Content
directory. Views/Shared/Site.Master
file, so that we can add some script references in. I am adding a reference to the latest jQuery, you might choose to use the jQuery that comes with the MVC template. Then we need to add a reference to jquery.nyroModal-1.6.2.js
(the latest version of nyroModal
at the time of writing). We also need to add a reference to nyroModal.css
.Views/Shared/Site.Master:
<head runat="server"> <title><asp:ContentPlaceHolder ID="TitleContent" runat="server" /></title> <script src=http://code.jquery.com/jquery-1.4.2.min.js type="text/javascript"></script> <script src="../../Scripts/jquery.nyroModal-1.6.2.js" type="text/javascript"></script> <link href="../../Content/nyroModal.css" rel="stylesheet" type="text/css" /> <link href="../../Content/Site.css" rel="stylesheet" type="text/css" /> <asp:ContentPlaceHolder ID="head" runat="server" /> </head>
Product
and ProductRepository
class. You should also have a Products.aspx
page that iterates over a collection of products for display on the page (if not, grab a copy of those files). In the Products.aspx
page, remove the existing JavaScript that writes the product details into the top of the Products
page. ProductDetail.aspx
and GetProductDetail.ascx
files. With these in place and the previous JavaScript removed, you should have a working products page that shows the details on another page. div
that we used previously, so that when we load data into it in the page, they will not show inline with the rest of the page. It will then set the position to be absolute on the details div
, so that when we load data into the details div
, hidden or not, it won't shift the contents of the rest of the page.Views/Home/Products.aspx
<script> $(function () { $("#detail").css('visibility', 'hidden'), $("#detail").css('position', 'absolute'), }); </script>
list-item
. For each link we find, we will override the click
event of the link.Views/Home/Products.aspx:
$('a.list-item') .click(function () { ... });
div
is empty before we try to add something to it. We can do this by selecting the details div
by its ID, detail
. Then we will access the html
property of that div
and clear it out.Views/Home/Products.aspx:
$("#detail").html(''),
div
is empty, we can focus on adding the appropriate product details into it. We will do this by posting a request to our GetProductDetail
action in the home controller. However, instead of using the GetProductDetail.ascx
partial view, we want to return some JSON directly to the calling JavaScript. To do this, we will need to add a new action to our home controller. This action will simply load the appropriate product and serialize it to JSON using a JsonResult. Because we already have an action named GetProductDetail
that takes in a product ID, we have two options—we can either add an unused parameter to our action or we can alter the name of the action, allowing us to create a new method signature. I am opting for a slightly different name by prepending an underscore.Controllers/HomeController.cs:
[HttpPost] public JsonResult _GetProductDetail(int id) { Product p = new ProductRepository().GetProductByID(id); return Json(p); }
_GetProductDetail
action. In this case, we will use jQuery to post a request to our _GetProductDetail
action passing along the product ID. This action will then serialize a Product
object and pass it back to us. To do something with this data, we will also write a callback function that takes in a data
parameter.Views/Home/Products.aspx:
.click(function () { $("#detail").html(''), $.post('_GetProductDetail', { id: this.id }, function(data) { }); });
div
. We will need another one to handle the formatting of each of the properties of the Product
class.Views/Home/Products.aspx:
$(function () { ... .click(function () { $("#detail").html(''), $.post('_GetProductDetail', { id: this.id }, function (data) { showProduct(data); }); return false; }); }); function showProduct(data) { $("#detail").html( formatLine('Id',data.ProductId) + formatLine('Name',data.Name) + formatLine('Price',data.Price) + formatLine('SKU',data.Sku) + formatLine('Created',data.CreateDate) + formatLine('In Stock',data.InStock) + formatLine('Desc',data.Description) ); } function formatLine(label, value) { return '<div class="display-label">' + label + ':</div><div>' + value + '</div>'; }
Products
page. You will see a listing of products, all of which you can click on. Clicking on a link will make a request to get the appropriate product. That product will then be serialized and returned to the client. The product will then be formatted and pushed into our details div
, but nothing will show on the page! In order to get our product details to show on the page, we need to hook up the nyroModal
window. This is one line of code calling the nyroModalManual
function with some display settings right after we call the showProduct
function that we just created.Views/Home/Products.aspx:
$.nyroModalManual({ url: '#detail', minHeight: 150, minWidth: 300, width: 300, height: 150 });
ProductDetails
page!View/Home/Products.aspx:
.click(function () { $("#detail").html(''), $.post('_GetProductDetail', { id: this.id }, function (data) { showProduct(data); $.nyroModalManual({ url: '#detail', minHeight: 150, minWidth: 300, width: 300, height: 150 }); }); return false; });
Product Details
page.Describing how this process works outside of code is much easier to understand. When the page has loaded, a JavaScript (jQuery) runs and overrides the OnClick
event of the appropriate links on the page. In the new click event handler, we then make a request to get some serialized data from our home controller by calling the _GetProductDetail
action. Once this data has been returned to the client, we format it and store it in a div
. We then call our nyroModal
pop-up and tell it to display the data stored in the details div
.