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 is comments use the SCRIPT tag, so that the application server can recognize it:
<!--SCRIPT insert script comment here
-->
JavaScript vs. 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). Note how 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>
Note the following 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 could 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 could 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've 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 haven't 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 could 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 Uniform Resource Locator (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 PowerDynamo Reference.
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's 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, you'll be maintaining 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 handy
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
,
we 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 © 1999 Sybase, Inc. All rights reserved. |