|
OK, this is a little long, let's break it down to see what's going on here.
First, we do namespacing: by creating objects, and placing the function onto that object, we make sure that we don't accidentally have two init() functions in a page - such as when we're creating two different poll tags with init functions. We also need to check if those objects already exist before creating them - after all, we may want to have multiple namespaces placed onto the "jsfdemo" object.
Then, we define a module - we have an init() function, and inside that init() function, we also define a poll() function. The poll() function has access to the variables inside the init() function, but calling the init function multiple times results in multiple contexts. This is a pretty common pattern in JavaScript, but it does look awkward to folks coming from Java.
At the end of the file, after setting up the poll() function, we have the line:
token = window.setInterval(poll, increment);
Which sets up the poll - we're simply using the JavaScript setInterval function to periodically call the poll() function, every increment milliseconds.
When the poll function is called, we find the button, and click it. This will, in turn, trigger the Ajax call. Then, we determine if the timeout time has come, and if it has, we turn off the timer with the clearInterval call.
OK, a little kludgy - but it works, after a fashion. There are some problems with this approach: Since we're using the f:ajax tag, we need to use the UIComponent.findComponent syntax for locating the target to update - some may prefer this, some won't. And while having a button that you could "unhide" to restart the poll might be handy, in general it's just cluttering up your page. Also, if the server stops responding for some reason, you'll get pummeled with error alerts if you're in development mode.
So, let's go ahead and rewrite this to instead use the jsf.ajax.request function, provided by jsf.js in JSF 2.
We'll only have to make a few quick changes to do this, as well as adding error handling. First, in the component page, we'll say add an output script call. And, we'll also change the call to init to be wrapped inside a jsf.ajax.addOnError function call. This will add a function to the list of listeners that get called if there's an error on the page. Note that the init function itself is not the function that will get added - rather, it's return value will be what's added. And we'll make that return value be a function (you'll see it in a second). We also remove all the markup associated with the button.
<cc:implementation>
<span id="#{cc.clientId}">
<h utputScript name="jsf.js" library="javax.faces" target="head"/>
<h utputScript name="poll/poll.js" target="head" />
</span>
<script type="text/javascript">
/* <![CDATA[ */
jsf.ajax.addOnError(jsfdemo.poll.init("#{cc.clientId}","#{cc.attrs.interval}", "#{cc.attrs.timeout}", "#{cc.attrs.render}" );
/* ]]> */
</script>
</cc:implementation>
In the backing JavaScript, we're going to have to make two changes. We'll have to change the poll function, and we'll have to add a return value to the init function. Here's the entirety of the backing JavaScript file:
if (!window.jsfdemo) {
var jsfdemo = {};
}
if (!jsfdemo.poll) {
jsfdemo.poll = {};
}
if (!jsfdemo.poll.init) {
jsfdemo.poll.init = function init(id, inc, to, rend) {
var componentID = id;
var increment = inc;
var timeout = to;
var elapsed = 0;
var token = null;
var render = rend;
// If increment isn't set, or it's less than some reasonable value (50) default to 200ms
if (isNaN(increment) || increment <= 50) {
increment = 200;
}
// If timeout isn't set, default to no timeout
if (isNaN(timeout) || timeout == 0) {
timeout = -1;
}
var poll = function poll() {
jsf.ajax.request(componentID, null, {render: render});
if (timeout != -1) {
// Not an accurate timeout - but simple to compute
elapsed += increment;
if (elapsed > timeout) {
window.clearInterval(token);
}
}
}
token = window.setInterval(poll, increment);
return function cancelPoll(data) {
if (data.source.id == componentID) {
window.clearInterval(token);
}
}
}
} |
|