Introduction
What you will get from this article:
- An overview of developing gadgets using a base class with built in support for displaying loaded, loading, and connection error states
What you will not get from this article:
- An introduction to gadget development
- An introduction to ASP.NET AJAX Extensions
Background
Most gadgets that deal with remote data have three basic states: loading, loaded, and connection error. For the sake of simplicity I have intentionally ignored docked and undocked states.
When I set out to develop my first gadget, I was unhappy with how much code I needed to write to support displaying states. The code I had written seemed messy and more functional than object oriented. To solve this problem I created a base class that provides support for rendering display modes and encapsulates some of the basic gadget API.
Using the Code
Creating the HTML for your Gadget
Be sure to reference the MicrosoftAjax.js and Dowds.Gadgets.js files first in your gadget's HTML file.
<head>
<script type="text/javascript" src="Scripts/MicrosoftAjax.debug.js">
</script>
<script type="text/javascript" src="Scripts/Dowds.Gadgets.js">
</script>
<script type="text/javascript"
src="Scripts/##You_Gadgets_Javasctipt_File##.js"></script>
</head>
Instead of dynamically generating the HTML for each state the Dowds.Gadgets.Gadget class takes a simpler approach. It expects the gadget HTML file to have a DIV element for each state. They must have the following ids:
dataLoadedDisplay, for the div to show when the data is successfully loaded
dataLoadingDisplay, for the div to show while the data is loading
dataNotAvailableDisplay, for the div to show when there is a connection error
Each DIV should be absolutely positioned and have its CSS visibility set to hidden.
<body>
<div id="dataLoadedDisplay" style="position:absolute;visibility:hidden">
<table id="movieListings">
<tr><td class="percent"></td><td class="title"><div><a></a></div>
</td></tr>
...
</table>
</div>
<div id="dataLoadingDisplay" style="position:absolute;visibility:hidden">
<img src="Images/Icon_Spinner.gif" /> Getting Data…
</div>
<div id="dataNotAvailableDisplay"
style="position:absolute;visibility:hidden">
<img src="Images/Icon_Info.png" /> Service Not Available
</div>
</body>
Creating the JavaScript for Your Gadget
Create a new class using ASP.NET AJAX Extensions. Use the registerClass method to make it inherit from Dowds.Gadget.Gadget
Dowds.Gadgets.Movies = function()
{
Dowds.Gadgets.Movies.initializeBase(this);
this._data = null;
};
Dowds.Gadgets.Movies.registerClass("Dowds.Gadgets.Movies",
Dowds.Gadgets.Gadget);
Accessing remote data such as an XML file or a web service can easily be accomplished using the Sys.Net.WebRequest class provided by ASP.NET AJAX Extensions.
Dowds.Gadgets.Movies.prototype =
{
_requestData: function()
{
var wRequest = new Sys.Net.WebRequest();
wRequest.set_url
("http://i.rottentomatoes.com/syndication/rss/top_movies.xml");
wRequest.add_completed(Function.createDelegate
(this, this._processData));
wRequest.invoke();
}
}
Once the data is returned you'll need to call the _updateDisplay method of the Dowds.Gadgets.Gadget class. It does almost all the work to update the gadgets state. It updates the display based on the values of the _dataNotAvailable and _dataLoaded flags.
| _dataNotAvailable |
_dataLoaded |
DIV Displayed |
true |
true |
dataNotAvailableDisplay |
true |
false |
dataNotAvailableDisplay |
false |
true |
dataLoadedDisplay |
false |
false |
dataLoadingDisplay |
Before calling the _updateDisplay method be sure to update the _dataNotAvailable and _dataLoaded flags based on the success of your request.
Dowds.Gadgets.Movies.prototype =
{
...
_processData: function(executor)
{
if (executor.get_responseAvailable())
{ var movieDoc = executor.get_xml();
this._dataLoaded = true;
this._dataNotAvailable = false;
this._data = Dowds.Gadgets.MovieInfo.ParseFromDoc(movieDoc);
this._bindTable(this._data);
}
else
{ this._dataLoaded = false;
this._dataNotAvailable = true;
}
setTimeout(Function.createDelegate(this, this._requestData),
(4 * 3600000));
this._updateDisplay();
}
}
The _updateDisplay method should be called whenever the state flags change. You'll also need to add custom logic to update the UI with the data that is returned. In the example above I call _bindTable(this.data) to update the table in the dataLoadedDisplay DIV with the movie review data that was returned.
Opening a Flyout
If you open a flyout that is already open it loses focus and becomes grayed out. To avoid this, check and see if the flyout is already open and if it is, just refresh the data.
_link_onclick: function(e)
{
...
if(System.Gadget.Flyout.show)
{
this._updateFlyout();
}
else
{
System.Gadget.Flyout.show = true;
}
...
},
_updateFlyout: function()
{
var flyoutWindow = System.Gadget.Flyout.document.parentWindow;
flyoutWindow.moviesFlyout.reload(this._selectedMovieInfo);
}
Final Thoughts
It's very important that you avoid making your gadget look like something a developer designed. Try thinking of an object or metaphor you could use to visually represent your gadget. For example, I created a movie review gadget so a clap board is a fitting backdrop.
Additional Resources