Chapter 6 Writing DynaScripts
This section presents some simple scripts that introduce you to DynaScript.
The following example shows how to embed a
script into an HTML template. This script simply writes Hello
world
 to the HTML document that is generated
for the Web client.
 To create this script:
 To create this script:
first_template
A test template containing a simple script
<HTML> <TITLE>first_template</TITLE> <BODY> <H1>A test template containing a simple script</H1> </BODY> </HTML>
<BODY>
 tag,
enter:
<!--SCRIPT
    document.Write( "Hello world" );
-->
 To display the source code of this script:
 To display the source code of this script:
 To execute the script against the application
server:
 To execute the script against the application
server:
<HTML>
<TITLE>first_template</TITLE>
<BODY>
    Hello world
</BODY>
</HTML>
When this script is executed from the Web site, the Web server returns this to the Web client, which in turn interprets the HTML for the user:
Hello world
The script is embedded as a comment in the body of a minimal HTML document. An HTML comment is marked by a tag like this:
<!-- anything in here is a comment -->
DynaScript comments use the SCRIPT tag, so that the application server can recognize it:
<!--SCRIPT insert script comment here -->
JavaScript versus Dynamo 
   Be careful not to confuse JavaScript SCRIPT
tags with DynaScript SCRIPT tags; the syntax is very similar. 
<SCRIPT LANGUAGE="JavaScript">DynaScript uses this syntax:
<!--SCRIPT Comments can be included here -->
The body of the script consists of a single instruction:
document.Write( "Hello world" );
Here, document
 is
a predefined object that refers to the HTML
document being executed.
The statement optionally ends with a semicolon.
Objects have methods associated
with them. A method is a function that carries
out actions on an object. Write
 is
a method of the document
 object.
An object method can take arguments and carries
out actions, like a function or subroutine in other programming
languages. In this case, the argument to the method is the character
string "Hello world"
.
The Write
 method inserts
this string into the HTML document that is sent to the client when
the template is requested.
The following example script illustrates how scripts use variables and how expressions are evaluated and assigned to variables:
<!--SCRIPT
    quote = "Colorless green ideas" ;
    quote = quote + " sleep furiously" ;
    document.Write(quote) ;
-->
To try this script out, you can use the Sybase Central editor to replace the script in the template you created in the previous section.
The output from this script is:
Colorless green ideas sleep furiously
You do not have to declare variables (although
it is good practice to declare them anyway). The first line of this
script creates a variable called quote
 and assigns
it the value of the string "Colorless green
ideas"
.
The +
 operator
concatenates the two strings, and the resulting expression is assigned
to the variable quote
.
The last line sends the value of the variable as a string to the
HTML output.
Unlike variables in many compiled programming languages, DynaScript variables do not have fixed datatypes. The datatype of a variable is set whenever the variable is assigned a value. You can change the datatype of a variable by assigning it an expression of a different type.
While this is convenient for small scripts, it does require that you take care when working with variables.
The same applies to operators. For example,
the meaning of the +
 operator depends
on the expressions it is operating on. In the previous example, +
 was used
to concatenate two strings, but if it is operating on integer expressions rather
than string expressions, it adds rather than concatenates the expressions. Consider
the following script:
<!--SCRIPT
    sum = 123 ;
    sum = sum + 456 ;
    document.Write(sum) ;
-->
The output from this script is the following HTML string:
579
The value of sum is set to the integer 123
 in
the first line. In the second line, the +
 operator
acts on the two integers, and so adds them to produce the value 579
.
In the final line, this integer is converted to a string for output.
You can use the following control statements to allow looping or conditional execution of statements:
if-else
for
while
do-while
These statements use standard C syntax.
The following example illustrates the use of
the while
 statement:
<!--SCRIPT
    var i = 0;
    while ( i < 3 ) {
        svar = "This is paragraph " ;
        svar += (i + 1) + "<P>" ;
        document.WriteLn(svar) ;
        i++ ;
    }
-->
This script prints the following HTML:
This is paragraph 1<P> This is paragraph 2<P> This is paragraph 3<P>
Notice the way that the +
 operator
acts in this script:
(i + 1)
 it
adds two integers.
+
 operators
recognize a string, and combine the other variable with the string
by concatenation.
You can define and use functions in scripts, which allows you to encapsulate a set of instructions once in a document, and use it several times throughout the document.
The following example shows how to provide consistent custom formatting across headings in an HTML document:
<HTML>
<TITLE>Function testing</TITLE>
<BODY>
<!--SCRIPT
    function h1( headingString) {
        heading = "<H1><FONT SIZE=5><FONT COLOR='000080'>" + headingString + "</FONT></H1>" ;
        document.Write( heading ) ;
    }
    h1( "This heading formatted by a script" ) ;
-->
</BODY>
</HTML>
In this example:
h1
 function
is defined before it is invoked. 
h1
 function
does not return a value to the calling script, so it is called using
a simple statement. You can also return a value from a function
using the return
 statement,
in which case you typically call the function as part of an assignment
statement.
DynaScript is object-oriented. An object can have properties (data) associated with it, as well as methods (functions that act on the properties). You can use the predefined objects included with Dynamo, or create your own custom objects.
For example, you can create a class of
object called product
.
You can add properties to store all the information about a product
(such as the product ID, name, color, size, description, price,
and quantity in stock). You can also add methods that carry out
typical actions on the product, such as ordering a certain quantity.
There are two steps to using an object:
function
 or class
 statement.
this
.
new
 operator.
For example, the following class
 statement
defines the product
 class:
class product(id, name, size, color,
                    quantity, price) {
     this.id = id ;
     this.name = name ;
     this.size = size ;
     this.color = color ;
     this.quantity = quantity ;
     this.price = price ;
}
To create currentProduct
,
which is an actual object (or instance) of
the product
 class, use new
 with
the appropriate property values:
var currentProduct = new product(600, "Sweatshirt",
         "Large", "Green", 39, 24.00 ) ;
Using objects   In practice, you can have an application that
takes an ID from an HTML form filled out at a Web client, and use
that ID together with a SQL query to fill out the properties of
the currentProduct
 object.
Combining scripts with SQL queries and responding to user input
are discussed in later sections.
So far, the product
 class
has properties, but no methods to act on those properties. To add
a method to an object, you must:
For example, you could define an order
 method
for the product
 class,
which carries out the proper actions when a product is ordered:
function order ( orderQuantity ) {
    // order returns true if the order is successful,
    // false if stock is too low
    if ( this.quantity >= orderQuantity ) {
        this.quantity -= orderQuantity ;
        return ( true ) ;
    }    else {
        return ( false ) ;
    }
}
Since we have declared order
 as
a global function in our script, its definition must precede the
definition of the product
 class.
We can then make the order
 function
a method of product
 by
adding a line to the class definition:
class product( id, name, size, color,
        quantity, price ) {
     this.id = id ;
     this.name = name ;
     this.size = size ;
     this.color = color ;
     this.quantity = quantity ;
     this.price = price ;
     this.order = order ;
}
Since we have not added any new properties,
creating a new instance of the product
 class
is the same as it was before:
var currentProduct = new product(600, "Sweatshirt",
    "Large", "Green", 39, 24.00 ) ;
You can then use the order
 method
in a template as follows:
<!--SCRIPT
    var orderQuantity = 20 ;
    status = currentProduct.order( orderQuantity ) ;
    if (status) {
        document.WriteLn( "Your order for " +
             orderQuantity + " " + currentProduct.name
             + "s succeeded.") ;
        document.WriteLn( "Now in stock: " +
             currentProduct.quantity + ".") ;
    } else {
        document.WriteLn( "Your order for " +
            orderQuantity + " " + currentProduct.name
            + "s failed.") ;
        document.WriteLn( "We only have " +
            currentProduct.quantity + " in stock.") ;
     }
-->
Arrays are useful for keeping track of a collection of objects. Typically, you index a variable using integers, as in this example of three prices:
price = new Array(3); price[0] = 19.95; price[1] = 42.99; price[2] = 0.02;
A common programming construct is a loop that performs some action on each element of an array. The loop variable iterates over the index of the array, as in the following example:
for ( i = 0 ; i < price.length; i++ ) {
    document.WriteLn("Price of item #" +
        i + " = " + price[ i ] );
    }
This produces the following output:
Price of item #0 = 19.95 Price of item #1 = 42.99 Price of item #2 = 0.02
Some functions must be able to receive and act on user input from the Web client. This information is sent by the Web client when a form is filled out as part of the URL that retrieves the form.
For example, suppose the Web client displays a form containing a list box, a text box, and an Order button. The user selects a particular product from the list, enters the desired quantity in the text box, then clicks the button to order the product.
The Order button points to an order-processing template that has a URL of http://www.sybase.com/products/order.html. When the Order button is clicked, the Web client sends the URL along with arguments that specify the order information. For example, if the user orders 25 of product #600, the complete URL would be:
http://www.sybase.com/products/order.html?id=600&quantity=25
The question mark separates the address of
the document from the arguments supplied to the document. An ampersand
separates each of the arguments in the list. In this example, the
two arguments id
 and quantity
 are
sent, with values 600
 and 25
 respectively.
You can fill in the value of a supplied argument in the HTML part of a document by preceding the value with a dollar sign. For example:
<HTML> <TITLE>Displaying variables</TITLE> <BODY> The value of argument quantity is $quantity. </BODY> </HTML>
If this template is called with this URL:
http://address?quantity=25
the following HTML is returned to the Web client:
<HTML> <TITLE>Displaying variables</TITLE> <BODY> The value of argument quantity is 25. </BODY> </HTML>
You can also use arguments inside scripts.
The argument is a property of the document, which is a predefined
object. The actual value of an argument named quantity
 can
be accessed inside a script as:
document.value.quantity
The following script responds to user input for an order:
<!--SCRIPT
    var currentProduct = new product(600, "Sweatshirt",
        "Large", "Green", 39, 24.00 ) ;
    var orderQuantity = document.value.quantity ;
    var retval = currentProduct.order(orderQuantity) ;
    if (retval) {
        document.WriteLn( "Your order for " +
            orderQuantity + " " + currentProduct.name +
            "s succeeded.") ;
        document.WriteLn( "Now in stock: " +
            currentProduct.quantity + ".") ;
    } else {
        document.WriteLn( "Your order for " +
            orderQuantity +
            " " + currentProduct.name + "s failed.") ;
        document.WriteLn( "We have only " +
            currentProduct.quantity + " in stock.") ;
    }
-->
For information on passing values of a multiple selection list, see "value property" in the PowerDynamo Reference Manual.
DynaScript extends JavaScript to include inheritance, which is the ability to create a new class of object that extends an existing class. The new class inherits all of the properties and methods of the parent class, and adds its own properties and methods.
This is tremendously useful when you are dealing with objects that share characteristics. Instead of defining each object separately, you can identify the information and behavior that is common to them, then define the objects themselves as extensions of the common material.
For example, suppose that Acme Widgets has
some employees that are paid a salary, while others are paid by
the hour. You could define two separate classes, salariedEmployee
 and hourlyEmployee
,
with their own sets of properties and methods. Here is a simple
version:
class salariedEmployee(name, title, managerName,
     salary)
    this.name = name;
    this.title = title;
    this.managerName = managerName;
    this.salary = salary;
    function PrintNameAndTitle() {
        document.WriteLn("Name, title: " + this.name
            + ", " + this.title); }
    this.PrintNameAndTitle = PrintNameAndTitle;
    function PrintAllInfo() {
        document.WriteLn("Name: " + this.name);
        document.WriteLn("Title: " + this.title);
        document.WriteLn("Reports to: " +
            this.managerName);
        document.WriteLn("Salary: " + this.salary); }
    this.PrintAllInfo = PrintAllInfo;
}
class hourlyEmployee(name, title, managerName, wage)
    this.name = name;
    this.title = title;
    this.managerName = managerName;
    this.wage = wage;
    function PrintNameAndTitle() {
        document.WriteLn("Name, title: " + this.name
            + ", " + this.title); }
    this.PrintNameAndTitle = PrintNameAndTitle;
    function PrintAllInfo() {
        document.WriteLn("Name: " + this.name);
        document.WriteLn("Title: " + this.title);
        document.WriteLn("Reports to: " +
            this.managerName);
        document.WriteLn("Hourly wage: " + this.wage); }
    this.PrintAllInfo = PrintAllInfo;
}
Because there is a lot of duplication between
the two classes of employees, without inheritance you would maintain
two nearly identical sets of code. Suppose instead that we take
the common items (name
, title
, managerName
,
and PrintNameAndTitle
)
and move them into a new generic class called employee
:
class employee(name, title, managerName) {
    this.name = name;
    this.title = title;
    this.managerName = managerName;
    function PrintNameAndTitle() {
        document.WriteLn("Name, title: " + this.name
            + ", " + this.title); }
    this.PrintNameAndTitle = PrintNameAndTitle;
}
We can then change salariedEmployee
 and hourlyEmployee
 to
use this new employee
 class
as their common parent. To do this, we use the extends
 clause
of the class
 statement:
class salariedEmployee(name, title, managerName, salary)
    extends employee(name, title, managerName) {
        this.salary = salary;
        function PrintAllInfo() {
            document.WriteLn("Name: " + this.name);
            document.WriteLn("Title: " + this.title);
            document.WriteLn("Reports to: " +
                this.managerName);
            document.WriteLn("Salary: " + this.salary);
        }
        this.PrintAllInfo = PrintAllInfo;
}
class hourlyEmployee(name, title, managerName, wage)
    extends employee(name, title, managerName) {
        this.wage = wage;
        function PrintAllInfo() {
            document.WriteLn("Name: " + this.name);
            document.WriteLn("Title: " + this.title);
            document.WriteLn("Reports to: " +
                this.managerName);
            document.WriteLn("Hourly wage: " +
                this.wage);
        }
        this.PrintAllInfo = PrintAllInfo;
}
We can then try out the redefined classes by creating salaried and hourly employees, then printing their information:
var salaryEmp = new salariedEmployee("Ned Simpson", "Technical Writer", "Barney Burns", 80000);
salaryEmp.PrintNameAndTitle();
salaryEmp.PrintAllInfo();
document.WriteLn("");
var hourlyEmp = new hourlyEmployee("Marge Flanders", "Contractor", "Barney Burns", 25);
hourlyEmp.PrintNameAndTitle();
hourlyEmp.PrintAllInfo();
This produces the following output:
Name, title: Ned Simpson, Technical Writer Name: Ned Simpson Title: Technical Writer Reports to: Barney Burns Salary: 80000 Name, title: Marge Flanders, Contractor Name: Marge Flanders Title: Contractor Reports to: Barney Burns Hourly wage: 25
There are several things to note here:
salariedEmployee
 and hourlyEmployee
 classes do not have their own PrintNameAndTitle
 methods,
so they automatically use the PrintNameAndTitle
 method
of the employee
 parent
class.
PrintNameAndTitle
 methods,
which would be used instead of the parent class's PrintNameAndTitle
 method.
This is called overriding a parent method.
PrintAllInfo
 method is polymorphic;
that is, you can call PrintAllInfo
 for
instances of salariedEmployee
 and hourlyEmployee
,
and they each respond in their own way. This is especially convenient
when looping through arrays of objects, since you can use the same
method call on each object (instead having to use if
 statements
to call methods like PrintAllSalariedInfo
, PrintAllHourlyInfo
,
and so on).
salariedEmployee
 and hourlyEmployee
,
you would not ordinarily create instances of the parent class employee
--it
is designed as an abstract class that simply
collects the common properties and behavior.
employee
 and
add the appropriate properties and methods (including a PrintAllInfo
 method). 
| Copyright © 2001 Sybase, Inc. All rights reserved. |   | |