Creating an OO Auction


Picture yourself at Sotheby’s dressed formally and ready to hold up a bidding paddle. Well, if that’s too much to contemplate, think of bidding for your favorite tchatshke on eBay.

Because a tchatshke is a thing, or an object, what’s a more fitting demonstration of object-oriented programming than an application that implements a tchatshke, or “thing,” auction?

tchatshke, n. [Yiddish] A thing as in a tourist souvenir; a tacky object displayed in one’s house; a small gift; something for sale on eBay; a bauble or trinket.

Real Programs Can Be Tough and Tricky

Advanced

A program that actually does something substantive can be a tricky thing to write. Complexity adds up quickly, and there are usually many different possibilities you have to take into account. A fully realized program needs to be able to appropriately respond to any possible user input or action, and that can be a pretty tall order. (Who the heck knows what people are going to do, anyway?)

The JavaScript Tchatshke Gulch program I’m about to explain includes some of the features of an eBay-style auction. (I’ll detail exactly what the program implements in the text.) Even though only a small subset of the features of a “real” auction application such as the eBay site are included, and there’s little in the way of user input validation, it’s still a complex program, by far the most complicated in this book so far. (The runner up for complexity so far is the Rock, Scissors, and Paper program in Chapter 3, “ Using Conditional Statements.”) This leads to a couple of points we should discuss.

Don’t worry if you don’t get everything about how this program works at this point. I’ve tried to explain it as best I can, and the fact that the program is object-oriented makes its underlying structure clearer (one of the great benefits of OO!). However, this is just not that easy a program. So, read through the text and code! You’ll get something out of it, even if you don’t “get” absolutely everything.

Another suggestion is that you come back later—perhaps after you’ve worked through the rest of this book. I’ll bet just about anything that you’ll find it much easier to understand the Tchatshke Gulch program!

As I’ve previously said, I’m a great believer in learning by doing. So my last suggestion is that you modify Tchatshke Gulch to make it yours—and learn about the program in the process. My thinking is that the process of modifying and extending the code will ensure that you learn how the program works. Learning by changing existing program code has worked well for me in my career as a professional programmer. You’ll find some suggestions for extending Tchatshke Gulch in the penultimate section of this chapter.

On a slightly different topic, it’s also the case that JavaScript code written using Notepad (or SimpleText on the Mac) is neither the best programming language nor the best programming environment for writing a program as complex at Tchatshke Gulch. This has both good and bad implications.

The main problem is the programming editor. In a sophisticated, modern programming editor, syntax errors are highlighted as they’re made. Additionally, object hierarchies and their members are usually available via drop-down lists as you create code—so you don’t have to remember, look up, or (fate forefend) misspell identifiers.

The moral here is that when you start to create serious production programs, you’ll want to do so in a serious programming environment.

However, in the meantime, there are some benefits to working in a “primitive” programming environment. True, it’s easier to make mistakes and harder to find them when you do. But to get things right, you’ll need to understand them fully. It’s a little bit like what some people believe about driving: Learning to drive a shift car makes you a better driver because you understand the car better, even if you only drive automatics in “real life.”

You’ll find techniques and tips to help you debug JavaScript code written under “primitive” conditions in Chapter 10, “ Error Handling and Debugging.”

What Tchatshke Gulch Does

What a program does is sometimes called its specifications. Creating rigorous and useful program specifications is an important and difficult task that’s one part art and one part science. Getting the specifications right is an important condition precedent to successfully writing programs that perform complex tasks. Indeed, creating a written specification document is usually the first deliverable in large-scale commercial software projects.

In brief, here’s what our Tchatshke Gulch program will do. (Even a brief look at buying or selling something on eBay should give you an idea of how much it doesn’t do!)

To start with, the user can create an auction by supplying a lot number, a description, a starting bid, and a bid increment as shown in the upper left of Figure 7-14. By the way, it’s common to show pictures of the user interface as part of a formal program specification.

click to expand
Figure 7-14: The Tchatshke Gulch user interface

Once an auction has been started, a new one can’t be created until the current one is closed. This is implemented in the user interface shown in Figure 7-14, which is shown in mid-auction because the Create Auction button is disabled. The Create Auction button is enabled when the user discovers the winner and ends the current auction by clicking Close Auction.

With an auction active, a bidder can enter a bid by supplying a name and maximum amount as shown in the upper right of Figure 7-14.

The auction uses a system called proxy bidding by eBay, in which the user enters a maximum that they’re willing to pay, but the system bids the least amount necessary to win the object for the user. To take an example, if a bidder enters a maximum bid of $200, and the highest other bid is $100 with a $5 bidding increment, then the bidder wins the auction for $105.

Note that, as at eBay, bids can only be entered if they’re greater than the current bid (or the starting bid) plus the increment.

The three large horizontal boxes at the middle and bottom of the interface shown in Figure 7-14, created using HTML <textarea> form elements, are used to display information about the auction. The top box shows general information about the auction. The middle box shows the current high bid.

When the Display Bids button is clicked, it displays the bids entered in the bottom <textarea> box. These are shown as entered, not as subsequently updated resulting from proxy bids.

When the Update Bids button is clicked, each bid is updated once to reflect the fact that an initial bid may have a higher proxy bid value than a later bid. However, the ultimate auction winner isn’t determined until the Close Auction button is clicked, which also is used to set the interface up so another auction can be started. The formula used for determining the amount paid by the high bidder is that the bidder with the highest proxy value wins. This bidder pays either the proxy value or the second highest proxy value plus the bidding increment, whichever is less.

Tchatshke Gulch Objects

I think you’ll agree that implementing the functionality behind the interface I just described as a bunch of functions and procedures without an OO framework would be a daunting task. Okay, so go ahead—put down this book and try if you don’t believe me.

The problem really is that you can have many bids, all of which have to be repeatedly compared to each other. There has to be a way to generalize these bids so that once you’ve learned how to treat two of them, you more or less know how to treat an arbitrary number of them. This insight makes plain what the OO structure behind Tchatshke Gulch ought to be: We’ll need an Auction object and Bid objects. One of the properties of the Auction object should be an array containing all the extant Bid objects, providing a convenient way to manipulate bids. Figure 7-15 shows this relationship.

click to expand
Figure 7-15: The Auction object contains an array of Bid objects.

The Auction object will also need properties to track the initial bid and the bidding increment for the auction.

Each Bid object will have a property for its current bid value and its maximum proxy bid value.

We will need constructors for both Bid and Auction objects. In addition, the Auction object will require methods for displaying bids, updating bids, and closing the auction to declare a winner.

If we can cleanly design the prototypes for these simple objects and their members, it shouldn’t be too big a deal to write the code that glues them together to create—ta dah!—Tchatshke Gulch.

Implementing the Bid Object

Listing 7-10 shows the Bid object constructor, which establishes a name, a maximum amount (or proxy bid), and a property for the current amount of any bid. In addition, it’s nice to implement a toString method for the Bid object prototype so that bids can be displayed with the required information simply by calling a Bid object’s toString method.

Listing 7.10: The Bid Object Constructor and Prototype

start example
 function Bid (name, max_amount, curr_amount) {      this.name = name;      this.max_amount = max_amount;      this.curr_amount = curr_amount;  }  Bid.prototype.toString = function(){      return this.name + ": current bid: " + this.curr_amount +      " Max amount (proxy bidding): " + this.max_amount;  }  Bid.prototype.valueOf = function() { return this.curr_amount;} 
end example

I’ve also included a valueOf method to make comparison between two Bid objects easy. Using the valueOf method on Bid objects, you can use the numerical comparison operators to see if the current value of one bid is greater than another.

Advanced

It’s worth noting that the functions used to implement both the toString and valueOf methods are never named and are what’s called a function literal, or lambda, explained in the sort function discussion in Chapter 6, “ Programming with Arrays.”

The Auction Object

The Auction prototype object is conceptually almost as simple as the Bid object. However, the methods that actually “run” the auction are part of the Auction object. These methods—makeBid, displayBids, updateBids, and endAuction—involve a bit of complexity.

Let’s start by looking at the code for the Auction object, as shown in Listing 7-11.

Listing 7.11: The Auction Prototype Object

start example
 function Auction (lot_num, desc, start_bid, increment){     this.lot_num = lot_num;     this.desc = desc;     this.start_bid = start_bid;     this.increment = increment;     this.bidArray = new Array();     this.status = "";     this.currBid = start_bid;  }  function display_Bids (){     var displayStr = "";     for (var i = 0; i < this.bidArray.length; i++){          displayStr += this.bidArray[i].toString() + "\r\n";     }     window.document.resultForm.txtBids.value = displayStr;  }  function update_Bids () {      var winnerIndex = 0;      for (var i = 0; i < this.bidArray.length; i++){           if (Number(this.bidArray[i].curr_amount) < Number(this.currBid)){              if (Number(this.bidArray[i].max_amount) >=                 Number(this.currBid) + Number(this.increment)){                    this.bidArray[i].curr_amount = Number(this.currBid) +                       Number(this.increment);                    this.currBid = this.bidArray[i].curr_amount;                    winnerIndex = i;                 }              }        }        window.document.resultForm.txtCurrentHighBid.value =            "Current High Bid: " + this.currBid + "\r\n" +             this.bidArray[winnerIndex].toString();        this.displayBids();     }     function end_Auction () {        var winnerIndex = 0;        var highBid = 0;        for (var i = 0; i < this.bidArray.length; i++){           if (Number(this.bidArray[i].max_amount) > Number(highBid)){              highBid = Number(this.bidArray[i].max_amount);              winnerIndex = i;           }        }        var runnerUpIndex = 0;        var runnerUpBid = 0;        for (var i = 0; i < this.bidArray.length; i++){            if (Number(this.bidArray[i].max_amount) >              Number(runnerUpBid) & & (i != winnerIndex)){              runnerUpIndex = i;           }        }       var winningBid =  Math.min(Number(this.bidArray[runnerUpIndex].max_amount) +            Number(this.increment),  Number(this.bidArray[winnerIndex].max_amount));        this.bidArray[winnerIndex].curr_amount = winningBid;        window.document.resultForm.txtCurrentHighBid.value =           "The winner is " +           this.bidArray[winnerIndex].name + "\r\n" +           "Detail: " + this.bidArray[winnerIndex].toString();        this.displayBids();        window.document.createForm.btnCreateAuction.disabled = false;     }     function make_Bid (name, max_amount, curr_Bid) {         var thisBid = new Bid (name, max_amount, curr_Bid);         this.bidArray [this.bidArray.length] = thisBid;     }     Auction.prototype.displayBids = display_Bids;     Auction.prototype.updateBids = update_Bids;     Auction.prototype.endAuction = end_Auction;     Auction.prototype.makeBid = make_Bid;     Auction.prototype.toString = function(){        return this.desc;     } 
end example

The Auction object constructor defines the properties of an Auction object instance. It also creates a new array to be used to store Bid objects.

The makeBid Method

Let’s have a look at Auction object methods! The makeBid method is implemented with the function make_Bid, as you can see from this prototype assignment:

 Auction.prototype.makeBid = make_Bid; 

The make_Bid function is simplicity itself. It simply creates a new Bid object, using the Bid object constructor, and then adds the newly created Bid instance onto the end of the bid array associated with the Auction object instance:

 function make_Bid (name, max_amount, curr_Bid) {      var thisBid = new Bid (name, max_amount, curr_Bid);      this.bidArray [this.bidArray.length] = thisBid;  } 

The displayBids Method

Here’s the function that implements the Auction object’s displayBids method:

 function display_Bids (){     var displayStr = "";     for (var i = 0; i < this.bidArray.length; i++){          displayStr += this.bidArray[i].toString() + "\r\n";     }     window.document.resultForm.txtBids.value = displayStr;  } 

This is also not terribly complicated code (and, gee, haven’t you come a long way?). If you need a refresher on working with arrays, please review Chapter 6, “ Programming with Arrays.”

This code simply iterates through the array of bids associated with the instance of the Auction object. For each Bid object instance, its toString method is used to concatenate it to a display string.

Note

The escape characters \r\n are used to add a line break to the text string used for display, as I explain further in Chapter 9, “ Manipulating Strings.”

Finally, after the array loop is complete, the string containing all the Bid object instance information, one bid per line, is assigned to a <textarea> box in the HTML form. (Don’t worry, I’ll get to the HTML in a bit!)

The updateBids Method

We’re going up in the complexity world. The function that implements the updateBids method iterates through the array of bid instances:

  function update_Bids () {    var winnerIndex = 0;    for (var i = 0; i < this.bidArray.length; i++){         if (Number(this.bidArray[i].curr_amount) < Number(this.currBid)){            if (Number(this.bidArray[i].max_amount) >=               Number(this.currBid) + Number(this.increment)){                  this.bidArray[i].curr_amount = Number(this.currBid) +                     Number(this.increment);                  this.currBid = this.bidArray[i].curr_amount;                  winnerIndex = i;               }            }      }      window.document.resultForm.txtCurrentHighBid.value =           "Current High Bid: " + this.currBid + "\r\n" +           this.bidArray[winnerIndex].toString();      this.displayBids();  } 

If a bid’s current amount is less than the current high bid, and the bid’s proxy maximum is greater than or equal to the current high bid plus the increment, then the bid’s current amount is adjusted upward accordingly, and the value of the variable referencing the current high bidder is changed.

Finally, the winner is displayed, and the displayBids method (which we’ve already discussed) is called to display all the bids (this is an example of not having to do the same work twice, or code reusability).

Tip

The displayBids method is reused in a number of places in the auction application. After all, once you have it written and working, why bother to do it again? The moral is to try to generalize so that your code can be easily reused.

The endAuction Method

Here’s the function that implements the endAuction method:

 function end_Auction () {     var winnerIndex = 0;     var highBid = 0;     for (var i = 0; i < this.bidArray.length; i++){         if (Number(this.bidArray[i].max_amount) > Number(highBid)){             highBid = Number(this.bidArray[i].max_amount);              winnerIndex = i;         }     }     var runnerUpIndex = 0;     var runnerUpBid = 0;     for (var i = 0; i < this.bidArray.length; i++){         if (Number(this.bidArray[i].max_amount) >             Number(runnerUpBid) & & (i != winnerIndex)){             runnerUpIndex = i;         }      }     var winningBid =  Math.min(Number(this.bidArray[runnerUpIndex].max_amount) +            Number(this.increment),  Number(this.bidArray[winnerIndex].max_amount));     this.bidArray[winnerIndex].curr_amount = winningBid;     window.document.resultForm.txtCurrentHighBid.value =         "The winner is " +         this.bidArray[winnerIndex].name + "\r\n" +         "Detail: " +  this.bidArray[winnerIndex].toString();         this.displayBids();         window.document.createForm.btnCreateAuction.disabled = false;     } 

What this does is first identify the bid with the highest proxy bid value. Next, in another iteration through the array of bid instances, the second highest proxy bid value is found (by finding the highest value that doesn’t have an index equal to the first highest value!).

With the first and highest proxy values in hand, the amount the winning bidder pays is calculated using the min, or minimum, method of the Math object built into JavaScript and mentioned earlier in this chapter. The amount the winning bidder pays is the minimum of the runner up’s proxy value plus the increment and the winner’s proxy value. (Normally, this will be the runner up’s proxy value plus the increment.)

Finally, the results of the auction are displayed, and the CreateAuction button is enabled.

The HTML Form

So far, I’ve shown you straight program code for creating object prototypes and their members. You’d place all this within <SCRIPT> tags in the <HEAD> section of your HTML document so the objects, method, and properties are ready, willing, and able when you’ve loaded the document in your Web browser.

This is a book about the craft of programming and about teaching people to learn how to program, so I don’t want to get too bogged down in the specifics of HTML.

But without an HTML form to go with the objects, there won’t be an auction application for you to run. What? No Tchatshke Gulch? Perish the thought!

Before I show you the HTML, you should know that in this section I’ve removed the HTML <TABLE> tags for the sake of clarity. So, what you’ll see in Listing 7-12 is HTML form code. Including the <TABLE> tags would just be confusing. But if you run the code shown in the listings and wonder why it doesn’t look like the figures, it’s because the <TABLE> formatting codes are missing. You can have a look at these codes, which are solely used in this document for formatting, in Listing 7-13, which is the complete code and HTML for Tchatshke Gulch.

Listing 7.12: The Tchatshke Gulch HTML Form (Table Tags Omitted)

start example
 <BODY bgcolor="#FFFFFF" link="#0000FF"> <H1>Tchatshke Gulch</H1> <H3>World's smallest on-line marketplace</H3> <form name="createForm">  Enter lot number:<input type=text name="txtLotNum">  Enter description:<input type=text name="txtDesc">  Enter starting bid:<input type=text name="txtStartBid">  Enter bid increment:<input type=text name="txtIncrement"> <input type=button name="btnCreateAuction"     value="Create Auction" onClick="createAuction(txtLotNum.value,     txtDesc.value, txtStartBid.value, txtIncrement.value);"> </form> <! -- end of form for creating the auction --> <!-- bid form --> <form name="bidForm">  Enter your name:<input type=text name="txtName">  Enter maximum bid:<input type=text name="txtMaxBid"> <input type=button value="Place Bid"   onClick="placeBid(txtName.value, txtMaxBid.value);"> </form> <!-- end of bid form --> <! -- auction results form> <form name="resultForm"> <textarea name="txtAuctionStatus" cols=80 rows=6> </textarea> <textarea name="txtCurrentHighBid" cols=80 rows=4> </textarea> <textarea name="txtBids" cols=80 rows=5> </textarea> <input type=button value="Display Bids"     onClick="if (theAuction != null) theAuction.displayBids();"> </TD> <input type=button value="Update Bids" name="btnUpdate"     onClick="if (theAuction != null) theAuction.updateBids();"> </TD> <input type=button value="Close Auction"     onClick="if (theAuction != null) {theAuction.endAuction();       theAuction = undefined;}"> </form> <!-- end of auction results form --> </BODY> 
end example

Listing 7.13: Tchatshke Gulch (a Program for Implementing an Auction)

start example
 <HTML> <HEAD> <TITLE>Tchatshke Gulch - The world's smallest on-line marketplace</TITLE> <SCRIPT>   // Bid prototype object  function Bid (name, max_amount, curr_amount) {       this.name = name;       this.max_amount = max_amount;       this.curr_amount = curr_amount;  }   Bid.prototype.toString = function(){        return this.name + ": current bid: " + this.curr_amount +         " Max amount (proxy bidding): "           + this.max_amount;  }  Bid.prototype.valueOf = function() { return this.curr_amount;}  // Auction prototype object  function Auction (lot_num, desc, start_bid, increment){     this.lot_num = lot_num;     this.desc = desc;     this.start_bid = start_bid;     this.increment = increment;     this.bidArray = new Array();     this.status = "";     this.currBid = start_bid;  }  function display_Bids (){       var displayStr = "";       for (var i = 0; i < this.bidArray.length; i++){            displayStr += this.bidArray[i].toString() + "\r\n";       }     window.document.resultForm.txtBids.value = displayStr;  }  function update_Bids () {       var winnerIndex = 0;       for (var i = 0; i < this.bidArray.length; i++){           if (Number(this.bidArray[i].curr_amount) < Number(this.currBid)){               if (Number(this.bidArray[i].max_amount) >=                  Number(this.currBid) + Number(this.increment)){                      this.bidArray[i].curr_amount = Number(this.currBid) +                         Number(this.increment);                  this.currBid = this.bidArray[i].curr_amount;                  winnerIndex = i;           }       }    }    window.document.resultForm.txtCurrentHighBid.value = "Current High Bid:  " +          this.currBid + "\r\n" +          this.bidArray[winnerIndex].toString();    this.displayBids();  }  function end_Auction () {       var winnerIndex = 0;       var highBid = 0;       for (var i = 0; i < this.bidArray.length; i++){           if (Number(this.bidArray[i].max_amount) > Number(highBid)){              highBid = Number(this.bidArray[i].max_amount);                 winnerIndex = i;           }       }       var runnerUpIndex = 0;       var runnerUpBid = 0;       for (var i = 0; i < this.bidArray.length; i++){          if (Number(this.bidArray[i].max_amount) >             Number(runnerUpBid) & & (i != winnerIndex)){                 runnerUpIndex = i;            }     }     var winningBid =  Math.min(Number(this.bidArray[runnerUpIndex].max_amount) +          Number(this.increment),  Number(this.bidArray[winnerIndex].max_amount));         this.bidArray[winnerIndex].curr_amount = winningBid;         window.document.resultForm.txtCurrentHighBid.value = "The winner is " +         this.bidArray[winnerIndex].name + "\r\n" +            "Detail: " +  this.bidArray[winnerIndex].toString();     this.displayBids();     window.document.createForm.btnCreateAuction.disabled = false;  }  function make_Bid (name, max_amount, curr_Bid) {     var thisBid = new Bid (name, max_amount, curr_Bid);     this.bidArray [this.bidArray.length] = thisBid;  }  Auction.prototype.displayBids = display_Bids;  Auction.prototype.updateBids = update_Bids;  Auction.prototype.endAuction = end_Auction;  Auction.prototype.makeBid = make_Bid;  Auction.prototype.toString = function(){     return this.desc;  }  window.status = "No auction active!";  var theAuction;  function createAuction(lot, desc, startBid, inc) {       if (lot == "" || desc == "" || startBid == "" || inc == "" ) {          alert ("You are missing a required value!");       }       else {           theAuction = new Auction (lot, desc, startBid, inc);           window.status = theAuction + " Auction is active!";           window.document.createForm.btnCreateAuction.disabled = true;           var displayStr = "Auction Active! Lot Number " + lot + "\r\n" +              "Description: " + desc + "\r\n" +              "Starting Bid: " + startBid + "\r\n" +              "Bidding Increment: " + inc + "\r\n";           window.document.resultForm.txtAuctionStatus.value = displayStr;           window.document.resultForm.txtCurrentHighBid.value = "";           window.document.resultForm.txtBids.value = "";       }  }  function placeBid (name, max_value){     if (theAuction == undefined) {        alert ("You must first create an auction before bids can be  placed!");        return;     }     if (name == "" || max_value == "" ) {        alert ("You must enter your name and your highest bid!");        return;     }     if (Number(max_value) < Number(theAuction.start_bid)) {        alert ("Sorry, bid less than minimum. Please try again!");        return;     }     if (Number(max_value) < Number(theAuction.currBid) +        Number(theAuction.increment)){        alert ("Sorry, your bid is less than the current bid " +  theAuction.currBid +            " plus the auction increment amount " + theAuction.increment  +            ". Please try again!");        return;     }     var curr_Bid = Number(theAuction.currBid) +  Number(theAuction.increment);     theAuction.currBid = curr_Bid;     theAuction.makeBid (name, max_value, curr_Bid);     window.document.bidForm.txtName.value = "";     window.document.bidForm.txtMaxBid.value = "";     window.document.resultForm.txtCurrentHighBid.value =         "Current High Bid: " + curr_Bid + "[" + name + "]\r\n" +  "Note that this does not reflect proxy bidding and maximum bids submitted. "           + "\r\n" +      "Click Update Bids to progress the auction.      Click Close Auction to determine the winner.";  }  </SCRIPT> </HEAD> <BODY bgcolor="#FFFFFF" link="#0000FF"> <H1>Tchatshke Gulch</H1> <H3>World's smallest on-line marketplace</H3> <! -- Outer table --> <TABLE> <TR> <TD> <! -- table and form for creating the auction --> <form name="createForm"> <TABLE cellspacing=8> <TR> <TD>Enter lot number:</TD> <TD> <input type=text  name="txtLotNum"> </TD> </TR> <TR> <TD>Enter description:</TD> <TD> <input type=text  name="txtDesc"> </TD> </TR> <TR> <TD>Enter starting bid:</TD> <TD> <input type=text  name="txtStartBid"> </TD> </TR> <TR> <TD>Enter bid increment:</TD> <TD> <input type=text     name="txtIncrement"> </TD> </TR> <TR> <TD> </TD> <TD> <input type=button name="btnCreateAuction" value="Create  Auction"     onClick="createAuction(txtLotNum.value,  txtDesc.value, txtStartBid.value, txtIncrement.value);"> </TD> </TR> </TABLE> </form> <! -- end of table and form for creating the auction --> </TD> <TD> <!-- bid table --> <form name="bidForm"> <TABLE cellspacing=8> <TR> <TD>Enter your name:</TD> <TD> <input type=text  name="txtName"> </TD> </TR> <TR> <TD>Enter maximum bid:</TD> <TD> <input type=text  name="txtMaxBid"> </TD> </TR> <TR> <TD> </TD> <TD> <input type=button value="Place Bid"      onClick="placeBid(txtName.value, txtMaxBid.value);"> </TD> </TR> </TABLE> </form> <!-- end of bid table --> </TD> </TR> <TR> <TD colspan=2                                                               > <! -- auction results table> <form name="resultForm"> <TABLE cellspacing=8> <TR> <TD colspan=3> <textarea name="txtAuctionStatus" cols=80     rows=6> </textarea> </TD> </TR> <TR> <TD colspan=3> <textarea name="txtCurrentHighBid" cols=80     rows=4> </textarea> </TD> </TR> <TR> <TD colspan=3> <textarea name="txtBids" cols=80  rows=5> </textarea> </TD> </TR> <TR> <TD> <input type=button value="Display Bids" onClick="if (theAuction !=  null)     theAuction.displayBids();"> </TD> <TD> <input type=button value="Update Bids" name="btnUpdate"  onClick="if (theAuction != null) theAuction.updateBids();"> </TD> <TD> <input type=button value="Close Auction"  onClick="if (theAuction != null)    {theAuction.endAuction(); theAuction = undefined;}"> </TD> </TR> </TABLE> </form> <! end of auction results table --> </TD> </TR> </TABLE> <! -- end of outer table --> </BODY> </HTML> 
end example

Gluing the Application Together

Oh, the ties that bind! There are a few more pieces we need to look at to tie this application together although we’re almost there.

Creating an Auction

First, if you look at the HTML code shown in Listing 7-12, there’s code assigned to each onClick event handler for the five buttons in the user interface (shown empty, or without any values entered, in Figure 7-16).

click to expand
Figure 7-16: The Tchatshke Gulch user interface (with no values)

When the Create Auction button is clicked, the following code in its onClick event gets processed:

 createAuction(txtLotNum.value, txtDesc.value,     txtStartBid.value, txtIncrement.value); 

This calls a function, createAuction, which isn’t the Auction object’s constructor. Instead, it takes care of some housekeeping and then calls the Auction constructor. Here’s the createAuction function:

   function createAuction(lot, desc, startBid, inc) {    if (lot == "" || desc == "" || startBid == "" || inc == "" ) {          alert ("You are missing a required value!");    }    else {       theAuction = new Auction (lot, desc, startBid, inc);       window.status = theAuction + " Auction is active!";       window.document.createForm.btnCreateAuction.disabled = true;       var displayStr = "Auction Active! Lot Number " + lot + "\r\n" +          "Description: " + desc + "\r\n" +          "Starting Bid: " + startBid + "\r\n" +          "Bidding Increment: " + inc + "\r\n";       window.document.resultForm.txtAuctionStatus.value = displayStr;       window.document.resultForm.txtCurrentHighBid.value = "";       window.document.resultForm.txtBids.value = "";    }  } 

This code checks to see that the user actually entered values in the text boxes in the HTML form. If the user did, the next (and crucial) step is to invoke the Auction object constructor:

 theAuction = new Auction (lot, desc, startBid, inc); 

By the way, there’s an important step I should point out. We’ll need to declare the variable to hold an instance of the Auction object, theAuction, outside of any function:

 var theAuction; 

By declaring the instance variable outside of all the functions, its scope, or the context in which it can be used, extends to all the functions in the HTML document.

A variable that can be used by all the functions in an application is sometimes called a global variable. Good programming practice is to have as few global variables as possible, both because having a lot of global variables violates the OO objective of object encapsulation and because global variables consume more system resources than local variables.

Placing a Bid

When the Place Bid button is clicked, the following code in the onClick event handler is processed:

 placeBid(txtName.value, txtMaxBid.value); 

Just as with creating an auction, the placeBid function does a few things besides invoking the Bid object constructor. Let’s have a look!

Here’s the code for the placeBid function:

 function placeBid (name, max_value){     if (theAuction == undefined) {        alert ("You must first create an auction before bids can be  placed!");        return;     }     if (name == "" || max_value == "" ) {         alert ("You must enter your name and your highest bid!");         return;     }     if (Number(max_value) < Number(theAuction.start_bid)) {        alert ("Sorry, bid less than minimum. Please try again!");        return;     }     if (Number(max_value) < Number(theAuction.currBid) +        Number(theAuction.increment)){        alert ("Sorry, your bid is less than the current bid " +  theAuction.currBid +           " plus the auction increment amount " +           theAuction.increment + ". Please try again!");        return;     }     var curr_Bid = Number(theAuction.currBid) +  Number(theAuction.increment);     theAuction.currBid = curr_Bid;     theAuction.makeBid (name, max_value, curr_Bid);     window.document.bidForm.txtName.value = "";     window.document.bidForm.txtMaxBid.value = "";     window.document.resultForm.txtCurrentHighBid.value = "Current High Bid:  " +     curr_Bid + "[" + name + "]\r\n" +     "Note that this does not reflect proxy bidding and maximum bids  submitted. "     + "\r\n" +     "Click Update Bids to progress the auction.     Click Close Auction to determine the winner.";     } 

This function first checks to see that an auction has been created. Good thinking! Without an auction, you can’t make a bid. It then checks to see that the user entered a name and the highest amount the user was willing to bid. Finally, the function checks to see that the bid is higher than the start price for the tchatshke being auctioned and also that the bid is higher than the current bid plus the increment.

If these conditions are met, the current bid amount is updated and the makeBid method of the Auction object instance is called:

 theAuction.makeBid (name, max_value, curr_Bid); 

Finally, the current bid is displayed.

The Other Auction Methods

The remaining three Auction object methods—displayBids, updateBids, and endAuction—are called directly from the onClick event handlers of the related buttons. So that you don’t have to go back and look at Listing 7-12, here’s the relevant HTML form code:

 <input type=button value="Display Bids"     onClick="if (theAuction != null) theAuction.displayBids();"> </TD> <input type=button value="Update Bids" name="btnUpdate"     onClick="if (theAuction != null) theAuction.updateBids();"> </TD> <input type=button value="Close Auction"     onClick="if (theAuction != null)       {theAuction.endAuction(); theAuction = undefined;}"> 

There’s not too much to say about the code in these onClick events because they call the Auction object methods pretty directly. But do note that they each, as a sanity check, test to see that an Auction object instance has been created:

 if (theAuction != null) ... 

You don’t want to go around calling the methods of an object instance when the instance hasn’t been created!

If you look at the onClick code for the Close Auction button, you’ll see that it “undefines” theAuction object after the auction has been completed for a last step, or finishing touch, in this application:

    onClick="if (theAuction != null)        {theAuction.endAuction(); theAuction = undefined;}" 

Finally, it may be helpful to show all the parts of this program in one fell swoop so you can see how they fit together. Listing 7-13 shows the entire Tchatshke Gulch.

Taking Tchatshke Gulch for a Test Drive

Enough talk! Enough code! Let’s take Tchatshke Gulch for a spin.

Open up the HTML document containing the Tchatshke Gulch code in your favorite browser. Enter some values to create an auction (see Figure 7-17).

click to expand
Figure 7-17: Creating an auction at the Tchatshke Gulch

With an auction created, you can now place a bid, as shown in Figure 7-18.

click to expand
Figure 7-18: Placing a bid at the Tchatshke Gulch

The “vital stats” for the bid are displayed, as shown in Figure 7-19.

click to expand
Figure 7-19: The bid value is shown in the Tchatshke Gulch user interface.

Go ahead! Enter some more bids! The more, the merrier (see Figure 7-20).

click to expand
Figure 7-20: Bids are shown together with the associated maximum proxy bid.

When you click the Close Auction button, the bidder with the highest proxy value wins (see Figure 7-21).

click to expand
Figure 7-21: And the winner is...

Note that the winner shown in Figure 7-21, Phyllis, pays $1,131, which is the correct amount: $2 (the increment) higher than the next-highest proxy bid ($1,129 bid by Nicholas).

Try This at Home Note

See what you can do to extend the Tchatshke Gulch application. This is the best way to learn about the objects that comprise this program. Can you add a reserve auction feature? Can you add a way to make bidders anonymous but keep track of them? What about changing the update function to take into account maximum proxy bids (in the current application this only happens when an auction is closed). All of these, and anything else you can think of, are great exercises to help speed you down your path toward becoming a totally awesome programmer!




Learn How to Program Using Any Web Browser
Learn How to Program Using Any Web Browser
ISBN: 1590591135
EAN: 2147483647
Year: 2006
Pages: 115
Authors: Harold Davis

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net