This tutorial is a tour of a JavaScript application that polls an eBay server for alerts about price change events on an item. The application, a badge widget, allows a user to input an item ID. The application uses a Shopping API call, GetSingleItem, to establish baseline information about the item (and retrieve its picture, which is displayed in the widget). The information about the item is then refreshed at intervals via the Client Alerts JavaScript SDK.
When you complete the tutorial, you will have an application that looks like this when it runs:

This tutorial contains the following sections:
You should know about the Client Alerts API and the Client Alerts JavaScript SDK before performing this tutorial:
The completed code for this application is provided as a sample in the Client Alerts JavaScript SDK. To get the complete source code, download and extract the SDK ZIP file, eBayClientAlertsJSSDK1.0.zip. The widget code is located in sample/ClientAlertsPublicChannelBadge.js. You'll have to set the appId property to your production AppID. To run the sample, load sample/ClientAlertsPublicChannelBadge.html in a browser.
In this step, you are creating a file called ClientAlertsPublicChannelBadge.js.
To create the initial code for forming your JavaScript SDK Client Alerts API call:
/**
* config object includes appId, affiliate tracking information, and siteId
* @type Object
*/
this.config = props.config;
/**
* item id.
* @type String
*/
this.itemID = props.item;
/**
* error message.
* @type String
*/
this.errorMessage = "";
this.channels = null;
/**
* Call GetSingleItem (Shopping API) to get item by itemid;
*/
this.getItem = function () {
var service = new com.ebay.shoppingservice.Shopping(this.config);
service.location = "http://open.api.ebay.com/shopping";
var fiRequest = new com.ebay.shoppingservice.GetSingleItemRequestType({itemID: this.itemID,
includeSelector: "Details"});
var url = service.getSingleItem(fiRequest, {object: this, success: this.onSuccess, failure: this.displayError});
};
/**
* callback function for error handling.
* @param {Array} errors error messages (com.ebay.shoppingservice.ErrorType)
*/
this.displayError = function(error) {
if (!this.errorMesage) {
this.errorMessage = error[0].longMessage;
} else {
this.errorMessage = this.errorMessage + "
" + error[0].longMessage;
}
var picture = image;
var bLyr = document.getElementById('alertsContent');
The callback setup above is followed, in the complete sample code, by a table definition for possible errors from the GetSingleItem call.
/**
* Callback function for Successful GetSingleItem response
*/
this.onSuccess = function(singleItemResponse)
{
this.displayItem(singleItemResponse);
this.start(singleItemResponse);
}
/**
* Start Channel and Session
* @param {Object} singleItemResponse
*/
this.start = function(singleItemResponse)
{
var item = singleItemResponse.item;
var bNoItem = false;
if (item === null) {
bNoItem = true;
} else if (item.listingStatus == 'Ended')
{
bNoItem = true;
}
if(!bNoItem) {
if(this.channels != null)
{
this.channels.stopAll();
}
// start a channel
//Set the proper polling interval in seconds here.
var pollingInterval = 30;
var channelType = "Item";
var eventTypes = ["PriceChange"];
// create channels object
var channelFactory = new com.ebay.clientalerts.api.ChannelFactory();
var channel = channelFactory.create(item.itemID, channelType, eventTypes);
// add channel to channels
this.channels = new com.ebay.clientalerts.api.Channels(this.config["appId"], pollingInterval);
this.channels.addChannel(channel);
// set call back function
this.channels.setChannelsListener(onChannelSuccess, errFunc);
// start all channels
this.channels.startAll();
}
}
If the user inputs another item ID and clicks this Go button, information and alerts for a new item will populate the badge.
/**
* Go button clicked.
*/
this.OnGoClick = function() {
var ChannelID = document.getElementById("ChannelID");
this.itemID = ChannelID.value;
this.getItem();
}
/**
* On page unload, to stop channel.
*/
this.stopChannel = function() {
if(this.channels != null)
{
this.channels.stopAll();
}
}
The next two sections show you how to create the callback functions. First, the response is validated. If the response is valid the call was successful and the response is formatted and stored so it can be displayed. If the response was not valid, the callback function needs to handle the exception.
/**
* Successfully received public messages.
* @param {Object} msg
*/
function onChannelSuccess(msg){
if(msg != null && msg != undefined && msg.length > 0)
{
// reset current price
if(msg[0].priceChange != null && msg[0].priceChange.currentPrice != null)
{
highlightCurrentPrice( msg[0].priceChange.currentPrice.currencyID
, msg[0].priceChange.currentPrice.value);
}
var mes = document.getElementById('message');
mes.innerHTML = new Date().toLocaleTimeString() + ":Item price is changed";
}
}
/**
* Error occured when receiving message.
* @param {Object} errorMsg
*/
function errFunc(errorMsg){
//var mes = document.getElementById('message');
//mes.innerHTML = new Date().toLocaleTimeString() + errorMsg.toJSONString();
alert("error:" + errorMsg.toJSONString());
}
In this sample, the success callback function for each call receives the call's response data and sends it to the display function of the UI.
Let's take a look at how this is done.
When you make an API call, the eBay web service returns data in its reponse. For instance, when you make the Client Alerts API GetPublicAlerts call, user data comes back in a JSON format, but the callback functions in the JavaScript SDK save the JSON response data as a JavaScript object.
If the a valid response was returned, the returned data
result will not equal null:
/**
* constructing HTML to display item badge
* @param {com.ebay.shoppingservice.FindItemResponseType} data FindItemsResponse data
*/
this.displayItem = function(singleItemResponse)
{
var item = singleItemResponse.item;
var bNoItem = false;
if (item === null) {
bNoItem = true;
} else if (item.listingStatus == 'Ended')
{
bNoItem = true;
}
var bLyr = document.getElementById('alertsContent');
if (!bNoItem)
{
var picture = item.pictureURL;
if (typeof(picture) != "undefined")
{
var loc = picture.toString().search(/[,]/);
if (loc > 1) {
picture = picture.toString().slice(0,loc);
}
}
//if (typeof(picture) === undefined) {
picture = image;
//}
var dStr = "<table cellpadding='0' cellspacing='0' width='220' height='350' border='0'>";
dStr = dStr + "<tr><td colspan='3'><img src='" + imgPath + "hover01.gif'></td></tr>";
dStr = dStr + "<tr><td width='1'><img src='" + imgPath + "1x1.gif' width='1' height='350'></td>";
dStr = dStr + "<td background='" + imgPath + "hoverbg01.gif' height='350' align='center' valign='top'>";
dStr = dStr + "<table cellpadding='2' cellspacing='0'width='210' align='center'>";
dStr = dStr + "<tr><td width='60' valign='top'><font face='tahoma,arial' size='2' color='#222222'>Item ID:</font></td>";
dStr = dStr + "<td><input name='ChannelID' type='text' id='ChannelID' value='" + this.itemID + "' size='12'/></td><td><input type='button' name='Go' id='Go' value='Go' onclick='vBadge.OnGoClick();'/></td></tr>";
dStr = dStr + "<tr><td colspan=3 align='center'><img src='" + picture + "' height='80' width='80' alt='No Image'></td></tr>";
dStr = dStr + "<tr><td colspan='3'></td></tr>";
dStr = dStr + "<tr><td colspan='3' height='10'><img src='" + imgPath + "1x1.gif' width='205' height='1'></td></tr>";
dStr = dStr + "<tr><td colspan='3' align='center'><b><font face='tahoma,arial' size='2' color='#222222' title='" + item.title + "'>" + eBayUtils.toBreakWord(eBayUtils.truncate(item.title, 45), 15) + "</font></b></td></tr>";
dStr = dStr + "<tr><td width='60' valign='top'><font face='tahoma,arial' size='2' color='#222222'>Time left:</font></td>";
dStr = dStr + "<td colspan='2'><font face='tahoma,arial' size='2' color='#222222'><span id='timeLeft'></span></font></td></tr>";
dStr = dStr + "<tr><td width='60' valign='top'><font face='tahoma,arial' size='2' color='#222222'>Bid count:</font></td>";
dStr = dStr + "<td colspan='2'><font face='tahoma,arial' size='2' color='#222222'><span id='bidCount'>" + item.bidCount + "</span></font></td></tr>";
dStr = dStr + "<tr><td width='60' valign='top'><font face='tahoma,arial' size='2' color='#222222'>Seller:</font></td>";
dStr = dStr + "<td colspan='2'><font face='tahoma,arial' size='2' color='#222222'>" + item.seller.userID + "</font></td></tr>";
dStr = dStr + "<tr><td colspan='3' height='10'><img src='" + imgPath + "1x1.gif' width='205' height='1'></td></tr>";
dStr = dStr + "<tr><td width='60'><font face='tahoma,arial' size='2' color='#222222'>Current price:</font></td>";
dStr = dStr + "<td colspan='2'><font face='tahoma,arial' size='2' color='#222222'><span id='currentPrice' style=''>"
+ item.convertedCurrentPrice.currencyID + " $" + item.convertedCurrentPrice.value.toFixed(2) + "</span></font></td></tr>";
dStr = dStr + "<tr><td colspan='3'></td></tr>";
dStr = dStr + "<tr><td colspan='3' height='10'><img src='" + imgPath + "1x1.gif' width='205' height='1'></td></tr>";
dStr = dStr + "<tr><td colspan='3' align='center'><font face='tahoma,arial' size='2' color='#222222'><span id='message' style=''>" +
"No Event!</span></font></td></tr>";
dStr = dStr + "<tr><td colspan='3'></td></tr>";
dStr = dStr + "<tr><td colspan='3' height='10'><img src='" + imgPath + "1x1.gif' width='205' height='1'></td></tr>";
dStr = dStr + "<tr><td width='80'><a href='" + item.viewItemURLForNaturalSearch + "' target='_blank'><img src='" + imgPath + "bidnow.gif' border='0'></a></td><td align='right'><img src='" + imgPath + "ebay.gif'></td></tr>";
dStr = dStr + "</table></td><td width='1'><img src='" + imgPath + "1x1.gif' width='1' height='350'></td></tr>";
dStr = dStr + "<tr><td colspan='3'><img src='" + imgPath + "hoverbt01.gif'></td></tr></table>";
bLyr.innerHTML = dStr;
var tl = new cdtime("timeLeft",item.endTime);
tl.display();
} else {
var bStr = "<table cellpadding='0' cellspacing='0' width='300' height='90'>";
bStr = bStr + "<tr><td width='300' colspan='3'><img src='" + imgPath + "tpimg.gif'></td></tr>";
bStr = bStr + "<tr><td width='7'><img src='" + imgPath + "ltimg.gif'></td>";
bStr = bStr + "<td width='286' background='" + imgPath + "bgwin.gif' align='center'>";
bStr = bStr + "<font face='tahoma,arial' size='5' color='#ffffff'>Item is ended</font></td>";
bStr = bStr + "<td width='7'><img src='" + imgPath + "rtimg.gif'></td></tr>";
bStr = bStr + "<tr><td width='300' colspan='3'><img src='" + imgPath + "btimg.gif'></td></tr></table>";
bLyr.innerHTML = bStr;
}
};
}
/**
* static entry function for search
* @param {Object} params.g_itemID item id.
*/
ClientAlertsPublicChannelBadge.goSearch = function(params)
{
var item = params.g_itemID;
if (item == null) {
item = document.getElementById("ChannelID").value;
}
var props = {};
props["appId"] = 'eBay008f8-4848-41ec-98d5-0c0b8b74992';
var config = new com.ebay.shoppingservice.ShoppingConfig(props);
var badge = new ClientAlertsPublicChannelBadge({config:config, item: item});
badge.getItem();
return badge;
};
function cdtime(pId, pDate)
{
if (!document.getElementById || !document.getElementById(pId)){
return;
}
this.lyr = document.getElementById(pId);
this.curTime = new Date();
this.endDate = pDate;
this.timesUp = false;
this.updateTime();
}
cdtime.prototype.updateTime = function()
{
var thisObj = this;
this.curTime.setSeconds(this.curTime.getSeconds()+1);
//update time every second
setTimeout(function(){thisObj.updateTime();}, 1000);
};
cdtime.prototype.display = function()
{
this.format = format;
this.showresults();
};
cdtime.prototype.showresults = function()
{
var thisObj = this;
//difference btw target date and current date, in seconds
var tdraw = (this.endDate-this.curTime);
td = (tdraw - this.endDate.getTimezoneOffset())/1000;
//if time is up
if (td<0){
this.timesUp = true;
this.lyr.innerHTML = this.format();
return;
}
//minute unit in seconds
var m = 60;
//hour unit in seconds
var h = 60*60;
//day unit in seconds
var d = 60*60*24;
var day = Math.floor(td/d);
var hour = Math.floor((td-day*d)/h);
var minute = Math.floor((td-day*d-hour*h)/m);
var second = Math.floor((td-day*d-hour*h-minute*m));
this.lyr.innerHTML = this.format(day, hour, minute, second);
//update results every second
setTimeout(function(){thisObj.showresults();}, 1000);
};
function format()
{
var tlStr="";
var intId;
//if target date/time not yet met
if (this.timesUp === false)
{
if (arguments[0] > 0){
tlStr = arguments[0] + "d ";
}
if (arguments[1] < 10) {
tlStr = tlStr + "0" + arguments[1];
} else {
tlStr = tlStr + arguments[1];
}
if (arguments[2] < 10) {
tlStr = tlStr + ":0" + arguments[2];
} else {
tlStr = tlStr + ":" + arguments[2];
}
if (arguments[3] < 10) {
tlStr = tlStr + ":0" + arguments[3];
} else {
tlStr = tlStr + ":" + arguments[3];
}
}
//else if target date/time met
else
{
tlStr = "Item Ended";
}
if (arguments[0] > 10) {
tlStr = "" + tlStr + "";
}
return tlStr;
}
function resetCurrentPriceColor()
{
var lyr = document.getElementById('currentPrice');
lyr.style.backgroundColor = "";
}
function highlightCurrentPrice(currencyID, price)
{
var lyr = document.getElementById('currentPrice');
lyr.innerHTML = currencyID + " $" + price ;
lyr.style.backgroundColor = "#E46062";
setTimeout(resetCurrentPriceColor, 2000);
}
var vBadge = null;
com.ebay.widgets.needs({
baseUrl:'http://w-1.ebay.com/js/2.0/min/',
resources: com.ebay.shoppingservice.Shopping.getSingleItem,
callback:
function() {
// replace it with correct path to your images
// e.g http://mywebsite.com/images/badge/
itemID = "270237294918";
vBadge = ClientAlertsPublicChannelBadge.goSearch({g_itemID: itemID});
}
});
Now you're ready to display the results.
Now that you have formatted the response and saved the data to an array, you want to display the data as a section within an .html document. This is about the simplest HTML page you can make, but it is a great base from which to build more interesting interfaces.
To present your results as an HTML page:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <script TYPE='text/javascript' SRC='http://w-1.ebay.com/js/2.0/min/Shopping.js'></script> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Client Alert SDK Sample</title> <link href="sample.css" rel="stylesheet" type="text/css" /> </head> <body> <script type="text/javascript" src="http://w-1.ebay.com/clientalerts/js/1.0/min/ClientAlerts.js"></script> <script type="text/javascript" src="ClientAlertsPublicChannelBadge.js"></script> <div id='alertsContent'></div> </body> </html>
List the files and resources required to execute the sample.
<script type="text/javascript" src="http://w-1.ebay.com/clientalerts/js/1.0/min/ClientAlerts.js"></script> <script type="text/javascript" src="ClientAlertsPublicChannelBadge.js"></script> <div id='alertsContent'></div>
Save your JavaScript file with a js file extension and your HTML file with a html file extension. For example, name the JS file ClientAlertsPublicChannelBadge.js and the HTML file ClientAlertsPublicChannelBadge.html.
As long as your web server is configured to work with JS, running your application is easy.
To run your application:
Refer to your web server documentation for information on how to deploy files onto your web server.
The browser should display a simple HTML page with seller information and listings for the seller specified in your HTML document.

Congratulations! You now have a working application that uses eBay Client Alerts JavaScript SDK.
This section contains observations about the tutorial and offers some alternate ways to achieve similar or better results. We've also provided some suggestions about where you can go from here.
As noted at the beginning of the tutorial, we tried to keep things simple. The eBay code samples page contains many excellent samples that are more complex and many give you good ideas for ways to design your applications.
The API call made by this application looks like the following:
http://clientalerts.ebay.com:8080/ws/ecasvc/ClientAlerts?ChannelDescriptor(0).ChannelType=PriceChange &ChannelDescriptor(0).ChannelID=190001080067&Version=555&callname=GetPublicAlerts
Here's a list of resources for the topics and technologies introduced in this tutorial:
In order to leave a comment in this section, you must view this Tutorial via the eBay web site: online version.
© 2008 eBay Inc. All rights reserved.
eBay and the eBay logo are registered trademarks of eBay Inc.
All other brands are the property of their respective owners.