DataCraft Code Sample: Netscape LiveWire and Server-Side JavaScript Full Screen

Maybe you've been wondering how to create a dynamic page like the following from your current database. The employee names are linked to an employee details page, and the email addresses are mailto links. To get this listing, the user invoked a URL that ended with a "?deptno=20".

This was produced with the DataCraft-authored code below, which will be included in a Fall 1996 Prima Publishing book on Netscape's LiveWire Pro. While currently a proprietary technology, LiveWire (formerly LiveScript) offers significant ease-of-development advantages over many of the alternatives. Furthermore, it meets our requirement of not using special DLLs or proprietary client-side software; all you need is a browser.

While this code doesn't get into too many subleties, it can at least get you started.


Typographic Conventions
Blue with UPPER CASE keywords Client-side HTML
Bold lower case Server-side JavaScript reserved word
Green Server-side comment
Plain text, lower case Server-side JavaScript variable, function, or operator

<HTML>
<HEAD>
<TITLE>MBM Computers:
<server>

   // The "<server>" tag indicates server-side JavaScript code that will be
   // processed by LiveWire.

   // This first section of code dynamically builds the document title depending
   // on whether the URL includes a department number using "...?deptno=nn" at
   // the end.  This page will show a table of employees for either the requested
   // department or for all departments.

   // LiveWire sets values for URL-encoded parameters in properties of the
   // built-in "request" object.

   if ( request.deptno != null )
        // The "write" function is one of the most commonly used in server-side
        // JavaScript; it simply sends HTML text to the client.
      write("MBM Computers: Department " + request.deptno + " Staff");
   else
      write("MBM Computers: All Staff");

</server>
</TITLE>
</HEAD>

<BODY>
<H1>

<server>
   // Here we use the same technique to construct a heading on the page.
   if ( request.deptno != null )
      write("Department " + request.deptno + " Staff");
   else
      write("All Staff");
</server>

</H1>

<server>
   // Call a programmer-defined function (see below) to verify the database 
   // connection.  Note that this ckDatabaseConnected function may redirect to a
   // login page; if that happens, we want to return here once the user logs in
   // successfully.  So we have to send the URL as a parameter.

   if ( request.deptno == null )
      ckDatabaseConnected("emps.html");
   else
      ckDatabaseConnected("emps.html" + "?deptno=" + request.deptno);
</server>

<TABLE BORDER>

<server>
   if (request.deptno == null)

      // Now comes the interesting part.  First we create a "cursor" object
      // using the built-in database.cursor method, which accepts a SQL select
      // statement as its argument.  We want the fields that we retrieve from the
      // database to vary based on whether there is a department number
      // qualifier.  Note that the double pipe (||) is concatenation, not the
      // logical OR.

      cursor = database.cursor("select deptno dept, "
                + "lname || ', ' || fname name, empno, "
                + "job_title, email, voice "
                + "from employees order by deptno, lname");
   else
      cursor = database.cursor("select "
                + "lname ||', ' || fname name, empno, "
                + "job_title, email, voice "
                + "from employees where deptno=" + request.deptno
                + " order by lname");

   // If there was any problem with opening the cursor, display as meaningful an
   // error message as possible.  See the implementation of this function below.

   showDatabaseError();

   // Shortly we're going to loop to construct an HTML table, with one row per
   // each record retrieved from the database.  First, create a row containing
   // column headings.  Note that "columns()" is a method returning the number
   // of columns in the cursor, and "columnName(n)" is a method which returns
   // the name of the nth column.

   write("<tr>");
   i = 0;
   while ( i < cursor.columns() ) {
      write ("<th>", cursor.columnName(i), "</th>");
      i++;
   }
   write("</tr>");

   // The "next()" method of a cursor object fetches the next row from the
   // database and puts the retrieved field values into properties of the
   // cursor object.  It returns true while there are records left to retrieve.
   // Values from a SQL SELECTed column named "x" would appear in the
   // cursor.x object property, and in cursor[n], where n is the ordinal array
   // index of the column.  The first column has n=0, not n=1.

   while (cursor.next()) {
      write("<tr>");
      i = 0;
 
      // We want values in two of the columns to show up as clickable links.
      // The first, NAME, will link to a page that displays more details about
      // the employee.  The URL will be encoded with the unique employee number.

       while (i < cursor.columns() ) {
          if (cursor.columnName(i) == "NAME") {
             write("<td nowrap>");
             write("<A HREF=\"editme.html?empno=" + cursor.empno + "\">");
             write(cursor.name, "</A></td>");
             }

             // The EMAIL column, naturally, will be a mailto link.  Notice in
             // both of these cases, we can escape the double quote character
             // with a backslash to include it in the write expression.

             else if (cursor.columnName(i) == "EMAIL") {
                               write("<td>");
                               write("<A HREF=\"mailto:" + cursor[i] + "\">");
                               write(cursor[i], "</A></td>");
             }
             else   // Plain data can simply be written like this:
                write("<td>" + cursor[i] + "</td>");
             i++;
         }
   }

   // It's important to close the cursor when we're done with it to free various
   // resources. 

   cursor.close();

   showDatabaseError();
</server>

</TABLE>

</BODY>
</HTML>

Server-side JavaScript allows the use of programmer-written functions such as "showDatabaseError" and "ckDatabaseConnected" used above. These reusable modules help the code stay compact and allow developers to add new features easily.
function ckDatabaseConnected( urlIn )

   // Call a function like this at the top of every HTML document that accesses
   // a database.  It checks to see if there is an existing database connection;
   // if not, it redirects to a login page, passing a "urlIn" parameter so the
   // user will automatically return to the document that originally called the
   // ckDatabaseConnected function.  This technique allows the user to bookmark 
   // any page and return to it gracefully.
{
   if (!database.connected())   // connected() is a method of the built-in
                                // "database" object. "!" is logical negation.
         if (urlIn == null)
            redirect(addClient("login.html"))
         else
            redirect(addClient("login.html?jumpTo=" + urlIn));

   // The "addClient" function is needed to properly maintain the client's view
   // of the URL since we are using a URL encoding scheme.
}


function showDatabaseError(statusIn)

   // To make a more robust application, call a function such as this after 
   // every JavaScript database operation.  For the database functions and 
   // methods that return a numerical status code, send the code as the
   // "statusIn" parameter.  Note that some database operations do not set
   // the status code, so you should also check for non-zero value returned
   // by database.majorErrorCode() method as in the first line below.
{
   if  ( statusIn != null || database.majorErrorCode() != 0 ) {

        // This code places the error message in-line on the current HTML
        // document.  It's also possible to simply redirect to a standard error
        // page, which would be a desirable alternative in many cases.

        if ( statusIn != null ) {
           write("<p>JavaScript Database Error " + statusIn + ": ");

           if      (statusIn == 1 )  write("Out of Memory");
           else if (statusIn == 2 )  write("Object never initialized");
           else if (statusIn == 3 )  write("Type conversion error");
           // else if... (There are a total of 27 predefined status codes.)

           write("<HR>");
        }
        write("<p>Database server or ODBC error: " + database.majorErrorCode()
             + " " + database.majorErrorMessage());
        write("<br>Vendor library error: " + database.minorErrorCode() + " "
             + database.minorErrorMessage() + "<br>");
        write("<hr>If you contact the helpdesk regarding this error, please "
             + "mail this message to <a href=\"mailto:helpdesk@chico.mbm.com\">"
             + "helpdesk@chico.mbm.com</a>");

   };
}

· · · · Latest Oracle Tip · · Contact · · DataCraft Home · · · ·