Blog Archives

Extending the Dojox Datagrid with Formatters

Posted in Inside TFG

I’m currently trying to create a Dojo widget that extends dojox.grid.DataGrid and has sub grids inside it. It’ll likely expand over time to be somewhat of a complex beast so there wasn’t really any other way than going the self contained widget. Having a bunch of global functions and DOM manipulation would be disgusting.

I’m building this widget in an incremental way so after getting the layout and hooking it up to a data source I moved on to creating a column with an expand/contract link that would trigger the sub grid to expand and contract as required. I ran into a problem when trying to keep my formatting functions contained within the widget definition.

I setup my layout in the following way :

 _mainGridLayout : [
      { type : "dojox.grid._RowSelector" },
      {
        cells : [[
          { name : '', get : this._getBlank, formatter : this._formatExpander },
          { field : "customer_id", name: "Cust ID" },
          { field : "customer_name", name : "Customer" },
          { field : "job_number", name : "Job No." },
            ...
        ]]
      }
    ],

I had defined the get function and formatter function in my widget, but whenever I loaded the widget I’d get a blank column as if neither function had been run.

After some poking and prodding it seemed that whatever context this view was being built in, the ‘this’ object was not my widget as I originally expected. The ‘this’ object was actually an instance of dojox.grid.cell. That was okay as a cell has a reference to it’s grid, so what I needed to do was access this.grid._formatExpander and this.grid._getBlank.

I did it in the following way :

          { name : '', get : function() {return this.grid._getBlank(arguments);}, formatter : function() {return this.grid._formatExpander(arguments);} },

It worked perfectly, I’d like to say just as I expected, but alas I’m not that smart :)

It feels to me like there should be a cleaner way to do it, but at least for the time being it works fine and doesn’t required me to move my formatting functions out into some global namespace and outside of my widget’s nice pieces of logic.

Keeping Context in Your AJAX Callbacks

Posted in Code, Tips and Tricks

These days I’m using a lot of asynchronous calls to get data and dynamically build the UI on the client side. It generally allows a far nicer experience to be provided to the user, being able to update parts of the UI without reloading the whole page is one of the first steps to your apps being able to wear a Web 2.0 moniker.

The general pattern for me these days has become :

var callback = function CallBack(data) {
    ... Do Some Processing ....
}

var input_data = GatherData();
MakeRequest(target_url, data, callback);

I tend to use jQuery and so my callback is passed in the returned data from the target_url. My call back function then generally performs some tasks on the UI based on what it receives.

The problem though is that in this pattern you can’t get any data from the context when MakeRequest() is called into the scope of CallBack. It’s a scoping issue that falls outside of this little post, but if you’d like an explanation of how Javascript handles scope of variables then you can Google for Javascript scope chain or take a shortcut to this article. Essentially when the call is made to CallBack() all it will have is it’s own variables and any globally accessible (window) variables.

This week though I had a thought and worked through it with one of my work mates, Tony. If you passed in a function that had the scope that included the context you wanted to pass, then maybe you’d be able to access whatever data from the callee you wanted. It turns out that this does work.

The way to do this is pretty simple, and I used it to create a simple function that would grab data and then populate a select element with options. In this case the context I’d like to keep is which select element is the target.

Say that I needed to run this over a bunch of select elements in quick succession then as the callbacks were issued they may end up out of the initial execution order, so the target element isn’t reliable if it’s been stored in a global variable. I could pass it in as a variable that would come back from the page that is returning the data but that just smells bad to me. I think potentially JSONP is an alternative too, but this felt like the right way.

$.getJSON(url, input_data,
	(function(target_element) {
		return function(response_data) {
			var html = [];

			for (var i = 0; i < response_data.length; i++) {
				item = response_data[i];

				html.push('


');
			}

			target_element.children(':gt(0)').remove();
			target_element.append(html.join(''));
		};
	})(target_element)
);

Essentially the main thing that has changed is that we are now running an anonymous function at the time that the AJAX call is issued. This anonymous function itself returns a function that matches the signature that jQuery is expecting for the callback function. The scope in which this function runs contains the target_element because it was passed into the anonymous function as a parameter. I’m tempted to say that it’s all crazy Javascript scoping, but in reality it’s very cool and very powerful.

If you want to see the execution order of this then just put a some logging into the anonymous function and the callback function and you’ll see what I mean. It will probably make it easier to see what is going on too.

I’ve run into issues trying to get around these problems before and thankfully as mine and the team’s knowledge of Javascript increases I’m finding better and better solutions. I thought my previous method of approaching this problem was quite hacky but now I don’t feel so dirty.

Thanks to Tony too for working through this with me!

Advanced Javascript with Douglas Crockford

Posted in Tips and Tricks

I’ve been slowly making my way through Douglas Crockford’s talk on Advanced Javascript and even at only about 3/4 of the way through the first installment I’ve learned plenty!

The presentation is in three parts and so far he’s covered a bunch of standard programming patterns and elements (singletons, private members, namespaces, constructors, etc…) implemented using Javascript as well as a detailed account of how the language is implemented. Rather than having to work out by trial and error what variables and functions are available where, or how to implement private functions or a singleton, he’s given you the first principles so you can work it out for yourself and a bunch of useful examples.

I highly recommend watching it. I find the more languages I learn the better I get at doing things across the board.

25 Tips for Better jQuery

Posted in Tips and Tricks, Websites or Tools

Typically these types of “25 Tips To…” or “10 Things That…” style articles have a few good points but are filled with fluff. However the article 25 Tips for Better jQuery is full of great points that cover architecture, coding conventions, compatibility and performance.

If you are looking to get a better handle on jQuery and more importantly how to use it well, I haven’t seen many better places to start.

Handling Permissions for AJAX Requests

Posted in Code, Tips and Tricks

Again I have a website where a lot of data transfer is done asynchronously and a large amount of the presentation is done using Javascript. Different users have different access to features across the site, and I can’t just rely on hiding links given the data is a simple HTTP request away. Protecting this data on the server side has always been easy to me, but I’ve typically found building the persistent abstractions I like to have far more difficult on the client side. As per usual, it’s probably just another issue I haven’t spent enough time to get a grip on.

It’s possible technologies such as Prism and Gears will help with this in the future. Unfortunately, it is the present.

This time I think I have a solution that I’m pretty happy with though. On the server side it involves using the existing HTTP response codes to indicate to the requester what happened with their request. On the client side the ajaxComplete() event is used to handle these codes.

jQuery will automatically call the function you specify as your callback in an AJAX request if the request is successful, so I’m only interested in handling failures. At the moment I’m assuming that all of my calls use JSON for their data format, but the alternative is a case I can handle later if need be. Only do what is necessary right now is a great credo I think.

So here is my event handler, it’s very simple but the documentation on the arguments to the event are a little slight. The success() call just makes a call to the function specified in the original call, hence passing in an empty array, simulating no records returned. The code I’m handling is for 401: Unauthorized, which in this case is the truth. This code will be sent back when I determine that the user is trying to access some data they aren’t supposed to. HTTP codes handle the majority of cases you’ll run into.

(function() {
	if (typeof(jQuery) != 'undefined') {
		jQuery().ajaxComplete(function(ev, req, settings) {
			if (req.status == 401) {
				settings.success([]);
				alert('You have insufficient privileges.');
			}
		});
	}
})();

The server side code is simple, it’s just a matter of sending back the appropriate header:

	header('HTTP/1.0 401 Insufficient Privileges', false, 401);

This function is specified in a global include where part of the website uses prototype, I’ve been slowly integrating jQuery. Therefore the first thing I do is check if jQuery has been defined, if it has then I register my function as the handler for the ajaxComplete event. Since it’s declared globally this will happen on every AJAX call. If the response code is 401 then first I pass back and empty array to my success handler so that the little loading notifier disappears, and then I notify the user of the error.

It seems to be a trend lately, but again this is just a very simple idea but I hope it saves someone some hassle. I know I’ve searched high and low on the topic and haven’t found a nice generic solution.

Twitter

The latest @rubyfive podcast is up, our own @sj26 receiving a mention for Ruby 1.9.3 performance improvements. http://t.co/hfx3EPMz

@frontiergroup about 1 day ago #

Search Posts

Featured Posts

Categories

Archives

View more archives