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