paul.nowak wrote: Matt, thanks for the comments. I made an error on the version of Plone. It's 2.5 Plone running on Zope 2.9x.
In regards to the additional products, we have a skin installed and we have a product that we had custom developed for us that connects to a PostgreSQL database. We've looked at slow PostgreSQL queries causing problems and have not been able to find an issue. We've also tested for the case where the PostgreSQL server is down and have not been able to create an issue. We therefor...
I frequently hear the question: "Does Dojo have an AJAX method that updates a div?" - The answer is that there's no Dojo-approved way of doing something like this. Updating a div is such an easy process, that implementing a de facto solution is not only extra code, but you also hit a wall as soon as you want to do "something more". The short and sweet solution looks something like this...
I frequently hear the question: "Does Dojo have an Ajax method that
updates a div?". The answer is that there's no Dojo-approved way of
doing something like this. Updating a div is such an easy process, that
implementing a de-facto solution is not only extra code, but you also
hit a wall as soon as you want to do "something more".
The short and sweet solution looks something like this:
This is a fine solution, but let's start discussing the DRY
philosophy. If you work with more than one node or URL (which you
probably will), and you want to process the HTML before you add it to
your document or update the DOM after you've made your innerHTML
assignment, you can end up with a lot of duplicated code. Armed with
some knowledge, and the power of functional programming, we can fix
this.
The load function in dojo.xhrGet is actually passed 2 arguments. The
second argument passed to the load function is the XMLHttpRequest
object that was used to make the call. Attached to this object is a
field named args, which contains the arguments originally passed to
dojo.xhrGet. This creates a handy way of passing information to your
load function.
So now, we can write a cool new function that we can share between our dojo.xhrGet calls. Let's call it loadIntoNode:
function loadIntoNode(data, xhr){ if(xhr.args.node){ xhr.args.node.innerHTML = data; } }
And then we can reduce our dojo.xhrGet call by replacing the load argument:
Notice that we've reduced the information here to the lowest common
denominators. Added is the the node field, which loadIntoNode is able
to access through xhr.args.node. With just a few more lines of code,
loadIntoNode could accept a dojo.query result as well.
We can even take this a step further and create a function that generates our dojo.xhrGet argument:
Which leaves us with the super-compact, super DRY dojo.xhrGet call:
dojo.xhrGet(intoNode("title", "title.php"));
Changing Things Up
So now you're saying: "But library X lets me do it differently". And it probably looks a little like this:
$("#quote p").load("content.php");
Dojo's $ equivalent is dojo.query. And if that's not good enough for you, just set the variable $ to dojo.query.
Here, the important functional method comes from dojo.NodeList, the
type of object dojo.query returns. It has a forEach function that
accepts a function that is called for each found node. In practice, it
looks like this:
If you've been following along, you should already know what to do
here: pass it a reusable function! Our only problem is that this
function is only called with a node, but it also needs a URL. How do we
fix it? Well first of all, we need to have a function that accepts a
URL. We also need this function, when called, to return a function that
we can pass to forEach.
But what does this function look like?
function loadFromQuery(url){ var html = ""; dojo.xhrGet({ url: url, sync: true, load: function(data){ html = data; } }); returnfunction(node){ node.innerHTML = html; } }
We've made this a synchronous dojo.xhrGet using the sync flag. What
this means is that code execution will pause until the html variable is
properly set and available to our returned function. It also means that
any chained functions that occur after this function is used will be
able to see the modified HTML.
So now you're saying: "I don't care if I can see the HTML or not, I
don't want I/O slowing down my code!" and that's cool, because there's
a solution. Let's rewrite our loadFromQuery function.
function loadFromQuery(url){ var get = dojo.xhrGet({ url: url }); returnfunction(node){ get.addCallback(function(data){ node.innerHTML = data; return data; }); } }
What's going on there?! Well, dojo.xhrGet returns something called a
Deferred. The short and sweet of it is that it's an object you can
attach callbacks to. If you attach a callback before the file finishes
loading, the callback waits until it's done. But, if it's finished
loading, the callback is made immediately. This allows our code to
execute without having to pause and wait for the file to finish loading.
Also notice that the callback function returns the data it was
originally given. This is because the next callback that gets added
uses the return from the previous callback. So you'll want to make sure
that's available.
So that's great, we have a function, but how do we use it? Well, like this:
And what I can't help pointing out at this point is where this
approach wins out over the solution mentioned at the beginning of this
section. The result of our loadFromQuery call is a function that we can
save to a variable and pass around as much as we want. It will never
have to make the Ajax call again or consult a cache. But I'll stop
talking about it and show it in action.
var result = loadFromQuery("script.php"); dojo.query("#title p").forEach(result); dojo.query("#section .subsection").forEach(result);
So there you have it. Because of Dojo's functional approach to code,
you can mix and match things to suit your project, without any
unnecessary code repetition.