Real-World Refactoring: Avoiding the "Reese's Cup" Problem
When you need to send data to the browser, sometimes it's easier to use existing HTML instead of coding a web page using JSON. Here is a technique on how to use your existing MVC code to perform the heavy lifting.
As a developer, you see a lot of interesting code in your career.
But when you see hard-coded HTML in JavaScript, or even C#, how do you refactor that into something you can use later?
When developers start mixing one language with another language, it can get messy really quick and simply unmanageable.
The Situation
Let's say you have a screen that initially displays a list of products. They are displayed in a grid which also has a button at the bottom that performs an AJAX call to retrieve the next set of products through JSON.
Most programmers receive the JSON data and start writing HTML in the JavaScript like so:
ajax call here...
var htmlData; $.each(dataReturnedFromAjaxCall, function(index,elem) { htmlData += "<tr>" + "<td>" + elem.title + "</td>" + "<td>" + elem.SKU + "</td>" + "<td>" + elem.manufacturer + "</td>" + "</tr>"; }); $(grid).append(htmlData);
Yikes!
While JavaScript doesn't require a compile process, I would definitely try to make this work with HTML instead of JavaScript.
The Solution
You want to make sure you call a service to retrieve HTML instead of performing the code above.
The key here is to make your HTML as modular as possible.
In the Controller, I created a method that returns a PartialViewResult.
[HttpPost] public ActionResult GetProducts(int? page) { var repository = new ProductsRepository(); var model = repository.GetProductsByPage(page); return PartialView("productRows", model); }
The Partial View is in the Views/Shared folder called productRows.cshtml
Views/Shared/productRows.cshtml
@model IEnumerable<Product> @foreach (var product in Model) { <tr> <td>@product.Title</td> <td>@product.SKU</td> <td>@product.Manufacturer</td> </tr> }
Now, you're JavaScript/jQuery becomes easier to work with when you aren't coding HTML in your JavaScript.
When you implement this type of solution, you don't have a "Reese's Cup" issue. You know..."Your peanut butter is in my chocolate! Your chocolate is in my peanut butter!"
Your JavaScript now looks like this:
$("#load-more-button").on("click", function() { var pageNumber = parseInt($("#main-section").attr("data-index")) + 1; $.ajax({ method: "POST", url: "/Home/GetProducts", data: { page: pageNumber } }) .success(function(data) { var tableBody = $("#gridView tbody"); tableBody.append(data); }); });
This keeps your code clean and separated.
Conclusion
This refactoring provides a simple and maintenance-free way of cleaning up your code in both JavaScript, C#, and HTML.
The whole idea is to make sure that you aren't creating more work for yourself through hard-coding HTML.
Would this be considered a Reese's Cup anti-pattern?
I can hear it now..."Why is your HTML in my C#?" or "Why is you HTML in my JavaScript?"
Was this a good refactoring? Post your comments below.