Dr. Dobb's is part of the Informa Tech Division of Informa PLC

This site is operated by a business or businesses owned by Informa PLC and all copyright resides with them. Informa PLC's registered office is 5 Howick Place, London SW1P 1WG. Registered in England and Wales. Number 8860726.


Channels ▼
RSS

JavaScript for the MVC example

, January 01, 2002


WebReview.com: JavaScript for the MVC example

The DOM in Version 5 Browsers

Let's look at the JavaScript that runs our example. In studying mvctable.js, a veteran DHTML coder will find some surprises due to its use of the new DOM.

/*
 mvctable.js v0.3 Monday, May 31, 1999
 Mitch Gould - [email protected]

 by Mitch Gould, [email protected]

 This script demonstrates dynamic documents in Netscape <br />Navigator and Internet Explorer 5 in the following ways:

  (a) it exercises W3C's standard Document Object Model API.
  (b) it creates, modifies, and destroys a table.
  (c) it partially illustrates the concept of model-view-controller.

 (To fully illustrate the MVC concept, modifications made to the
  data view would need to be propagated back to the data model.)

*/

// A. Data initialization.
 
 var datacount = 0
 model = new Array()

   // Allocate the first dataset, a set of quotations, from this array.
   arrayquotes = new Array(
    "Oh dear! I shall be too late.",
    "Curiouser and curiouser!",
    "Who are -you-?",
    "We're all mad here.",
    "Twinkle, twinkle, little bat.",
    "Off with her head!",
    "I make you a present of everything I've said...",
    "Once, I was a real Turtle.",
    "Sentence first—verdict afterwards.")
 
   // When a link is clicked, the quotations' sources will be revealed
   // from this array.
   arraysources = new Array(
    "White Rabbit",
    "Alice",
    "Caterpillar",
    "Cheshire Cat",
    "Dormouse",
    "Red Queen",
    "Dutchess",
    "Mock Turtle",
    "Red Queen")

// B. MVC-DOM methods.

 // Establish a new data model and assign it to a new view.
 function startController() {

  // Populate the model with initial data.
  datamodel = refreshModel(arrayquotes)

  // Get the document body element.
  var docbod = getBody()

  /* 
     Create a view in the body of the document and fill it
     with the initial data. 
  */
   createView(docbod, model) 
 }

 // Copy the specified dataset into the model.
 function refreshModel(arraycurrent) {

  // Populate the model with the current datastore.
  for(var i=0; i < arraycurrent.length; i = i + 1)
   {
    model[i] = arraycurrent[i]
   }
  return model
 }

 /* 
    this could be generalized to provide alternatives to a
    a table view, such as a select object, a tree, or even
    a textarea. this sample produces a one-column table. 
    Multi-column tables are more complex.
 */
 function createView(bodyelement, themodel) {
  table = document.createelement("TABLE")
  table.border = 1
  table.id = "viewtable"
  tablebody = document.createelement("TBODY")
  for(var i=0; i < model.length; i++)
  {
   currentrow = document.createelement("TR")
   currentcell = document.createelement("TD")      
   currentcell.appendchild(document.createtextnode(model[i]))
   currentrow.appendchild(currentcell)
   tablebody.appendchild(currentrow)
  }
  table.appendchild(tablebody)
  bodyelement.appendchild(table)
  return table
 }

 // refresh the model first, then the view.
 function refreshview(dataset) {
  // populate the model with new data.
  refreshmodel(dataset)

  tablebody = document.getelementsbytagname("TBODY").item(0)
  var count = 0
  replacealltext(tablebody)
 }

 // One can also destroy HTML objects using the DOM.
 function destroyView() {
  objecttodestroy = document.getelementbyid("viewtable")
  body = getbody()
  body.removechild(objecttodestroy)
  // now destroy the buttons.
  objecttodestroy = document.getelementbyid("whosaid")
  body.removechild(objecttodestroy)
  objecttodestroy = document.getelementbyid("goaway")
  body.removechild(objecttodestroy)
 }

// c. dom tree-navigation and utilities.

 /*
   One must climb the trunk, branches, and twigs to get
   (or set!) the fruit. The recursive nature of this
   algorithm reflects an essential fractal nature of 
   documents.
 */
 function replaceAllText(startelem) {
  // Climb the object tree, replacing its text nodes with
  // new data.
  for (var i=0; i < startelem.childnodes.length; i = i + 1) {
   switch (startelem.childnodes.item(i).nodetype) {
    case 1: // element nodetype
     replacealltext(startelem.childnodes.item(i))
     break;
    case 3: // text nodetype 
      if (datacount < model.length) {
       settext(startelem.childnodes.item(i), model[datacount])
       datacount = datacount + 1
      } else {
       settext(startelem.childnodes.item(i)," - ? - ")
      }
     break;
   } //endswitch
  } //endfor
 } //endfunction

 /*
    many operations on dynamic documents require one to start
    from the document's body element.
 */
 function getBody()
  {
   if(navigator.appName != "Netscape") {
    resultelement = document.body;
   } else {
    resultelement = document.getelementsbytagname("body").item(0);
   }
   return resultelement;
 }

 // utility function to overwrite text nodes.
 function settext(tagtoset, valuetoset) {
  tagtoset.nodevalue = valuetoset
 }

// d. this can't start until the page loads.
 window.onload = startcontroller
Listing 2. The JavaScript source for mvctable.js.

For the sake of clarity, mvctable.js is divided into four parts:

A. data initialization,
B. MVC-DOM methods,
C. DOM tree-navigation and utilities, and
D. load-event handler.

Section A is simply expected in a script of any size. Here, it sets up the string arrays that contain the Alice quotations and their sources.

The code in the B section provides a way to implement a model-view-controller design pattern using the Document Object Model. This section acts as the controller, initializing the model and view, refreshing the model and view with updated values, and destroying the view upon request.

Section C provides support routines that encapsulate lower-level details of access to document objects. It's a bit disappointing that the DOM doesn't provide standardized access to the document at this level of encapsulation, but once these utility methods are written, they can be reused endlessly. These methods are responsible for navigating the document tree to touch the desired objects, notably in this case, text content that must be replaced.

The D section is required to start the controller as soon as the browser finishes loading the page.

With this background, we're ready to examine the code example. As the page is loading, the browser processes the data initialization section, executing the constructor

 model = new Array()

to create an empty model, and creating two more arrays: arrayquotes and arraysources.

Initializing the controller

Once the page has finished loading, the controller starts.


// This can't start until the page loads entirely.
 window.onload = startController

The controller transfers the quotes to the model, and creates a new table in the document to act as a view, as shown in Listing 3.


// B. MVC-DOM methods.

 // Establish a new data model and assign it to a new view.
 function startController() {

  // Populate the model with initial data.
  datamodel = refreshModel(arrayquotes)

  // Get the document body element.
  var docbod = getBody()

  /* 
     Create a view in the body of the document and fill it
     with the initial data. 
  */
   createView(docbod, model) 
 }

Listing 3. The startController() function.

To understand the functions called by startController(), we must turn to a description of the DOM, which we'll cover in the next section.


JavaScript for the MVC example
Understanding the Document Object Model


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task. However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.