JQuery for Everyone: Minimal AOP and Elegant Modularity
If you read the previous articles on AOP, you know I’m a fan. It took some serious digging for me to understand how the JQ-AOP plugin works and how I could use it to fit my needs. I succeeded and I think you’ll really like the result.
But First, A Little About Objects
In JavaScript, we have two basic options for creating “plugins” (extensions of the jQuery library). Like my Print Any Web Parts code, you can create a jQuery method by using jQuery.prototype.
jQuery.fn.<method name>= function(options){…
JQuery is all about “Find Something and Do Something With It.” Most jQuery plugins look like the line above because they want access to this, the array of DOM elements returned by the selector, $(”<selector>”) = “find something.”
However, if you don’t need this (because you’re going to “do something” without the DOM) you can create another object and use it to extend jQuery. The original jquery-AOP code follows this second pattern. jQuery aop is not a method with access to this. The first line looks something like:
jQuery.aop = {
after : function(pointcut, advice)
…
I bolded the curly brace to emphasize that aop is an object (using the object literal notation) with parameters (stuff before a “:”) to define the methods.
A lot of modern JavaScript will follow one of these less-obtrusive patterns because it does not litter the global namespace.
What Are You Talking About Global Namespace?
Load up one of your SP pages in Firefox. Open the console window and type “window” then click Run. It will return the window object on the left-hand side. Now click window.

You will see a lot of stuff appear on the left side of Firebug. It starts off naming the global variables. These are variables that some SharePoint JavaScript created and couldn’t keep to itself. I counted over 400! After that, you’ll see global functions (methods attached to the window object). There are over 700 global methods! That’s your global namespace in SharePoint, and it’s sort of a mess.
At a minimum, this can raise the risk for namespace collisions, where functions or variables try to have the same name and end up overwriting one another–a very important consideration when you start mashing up various solutions from different authors.
A messy global namespace also obscures how code works because developers will avoid names like init() for a function because it’s probably already used while init() offers the best intuitive description of what the function does.
Before Modifying AOP
In my loadTip-AOP example, I had to use the .around() method to access the original function’s arguments, write the important arguments to the jQuery .data() cache then use the .after() method to retrieve the data and perform our custom function.
It works fine, but it lacks elegance. It’s logically cumbersome.
A Sleak, Trim AOP
Once I tapped into how AOP worked (not an easy feat for my little brain), I was able to pass the arguments (the stuff between the parentheses of the initial function invocation, e.g., ExpGroupRenderData(argument[0],argument[1],argument[2]) ) to my custom function using just one method, .after().
First, I removed everything I did not need from the original AOP code. Then I changed the return for the weave() function to include [arguments].
<script type="text/javascript"> (function(){ var weave = function(source, method, advice){ var old = source[method]; var aspect = function() { old.apply(this, arguments); return advice.value.apply(this, [arguments]); }; source[method] = aspect; return aspect; }; jQuery.aop = { after : function(pointcut, advice){ var source = (typeof(pointcut.target.prototype) != 'undefined') ? pointcut.target.prototype : pointcut.target; return weave(source, pointcut.method, { value: advice }); } }; })(); $(function(){ //call a custom function after ExpGroupRenderData using the original arguments $.aop.after({target:window,method:"ExpGroupRenderData"}, function(args){ if (args[2]=='true'){__custom_function__("#tbod"+args[1]+"_");} }); }); </script>
As you can tell from the last couple of lines, I still use the same notation to call AOP and weave my custom function, $.aop.after({target:…,method:”some_function”}, my_callback_function(){…});
What changed is that .after() now returns the arguments ExpGroupRenderData was passed when first called. In this case, I’m interested in args[2], “isLoaded” and args[1], “groupName.” (See the original SP code on line 1816 of init.js: function ExpGroupRenderData(htmlToRender, groupName, isLoaded)…)
Note: Since weave is a private variable within a closure, only aop has access to it. Typing “weave” in the console will tell you that “weave is not defined” while typing “aop” in the console will return an object with one method, after.
Why We Like IKEA
IKEA’s furniture is modular. If you buy one end table you have an end table. If you buy two end tables, you can either have two end tables or you can stack them to make a small bookshelf. Or stack 3 bookshelves to make an entertainment center. “Stackable” stuff makes it easier to configure for your particular needs.
A lot of people like this approach and have started websites like IKEA hacker to share their ideas. The ability to create something new from bits and pieces of something else makes IKEA popular. Sometimes the creativity unleashed by the modular approach allows for the creation of something novel.
Sticking with AOP means my solutions will be more modular, more like IKEA furniture. You should be able to mix, match, and stack the solutions in a variety of configurations to achieve your personal goals. With this latest bit of revision, I just made it more elegant. Instead of holding our bookshelves together with duct tape, they fit together naturally.
- JQuery for Everyone: Accordion Left Nav
- JQuery for Everyone: Print (Any) Web Part
- JQuery for Everyone: HTML Calculated Column
- JQuery for Everyone: Dressing-up Links Pt1
- JQuery for Everyone: Dressing-up Links Pt2
- JQuery for Everyone: Dressing-up Links Pt3
- JQuery for Everyone: Cleaning Windows Pt1
- JQuery for Everyone: Cleaning Windows Pt2
- JQuery for Everyone: Fixing the Gantt View
- JQuery for Everyone: Dynamically Sizing Excel Web Parts
- JQuery for Everyone: Manually Resizing Web Parts
- JQuery for Everyone: Total Calculated Columns
- JQuery for Everyone: Total of Time Differences
- JQuery for Everyone: Fixing Configured Web Part Height
- JQuery for Everyone: Expand/Collapse All Groups
- JQuery for Everyone: Preview Pane for Multiple Lists
- JQuery for Everyone: Preview Pane for Calendar View
- JQuery for Everyone: Degrading Dynamic Script Loader
- JQuery for Everyone: Force Checkout
- JQuery for Everyone: Replacing [Today]
- JQuery for Everyone: Whether They Want It Or Not
- JQuery for Everyone: Linking the Attachment Icon
- JQuery for Everyone: Aspect-Oriented Programming with jQuery
- JQuery for Everyone: AOP in Action - loadTip Gone Wild
- JQuery for Everyone: Wiki Outbound Links
- JQuery for Everyone: Collapse Text in List View
- JQuery for Everyone: AOP in Action - Clone List Header
- JQuery for Everyone: $.grep and calcHTML Revisited
- JQuery for Everyone: Evolution of the Preview
- JQuery for Everyone: Create a Client-Side Object Model
- JQuery for Everyone: Print (Any) Web Part(s) Plugin
- JQuery for Everyone: Minimal AOP and Elegant Modularity
- JQuery for Everyone: Cookies and Plugins
- JQuery for Everyone: Live Events vs. AOP
- JQuery for Everyone: Live Preview Pane
- JQuery for Everyone: Pre-populate Form Fields
- JQuery for Everyone: Get XML List Data with OWSSVR.DLL (RPC)
- Use Firebug in IE
- JQuery for Everyone: Extending OWS API for Calculated Columns
- JQuery for Everyone: Accordion Left-nav with Cookies Speed Test
- JQuery for Everyone: Email a List of People with OWS
- JQuery for Everyone: Faster than Document.Ready
- jQuery for Everyone: Collapse or Prepopulate Form Fields
- jQuery for Everyone: Hourly Summary Web Part
- jQuery for Everyone: "Read More..." On a Blog Site
- jQuery for Everyone: Slick Speed Test
- jQuery for Everyone: The SharePoint Game Changer
- JQuery For Everyone: Live LoadTip