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:
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 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. |