Foxhound is the better* Database Monitor for SQL Anywhere.
*better: More thorough, more relevant, more effective.
...more Alerts, more All Clears, more details, more control in your hands.
|
[Home] | [Back to Tip 73] | [Forward to Tip 75] | [Archives] |
Breck Carter
Last modified: November 21, 1997
mail to: bcarter@bcarter.com
(This Tip originally appeared on the PowerBuilder and Java Journal web site.)
Summary: NetImpact Dynamo lets you code web server-based database programs in a JavaScript-like language called Dynamo Script. By combining server-side Dynamo Script, client-side JavaScript and HTML code in the same web page you can automate many of the mundane tasks required in the creation of interactive web sites. And your whole web site can be stored in a single database to make administration, publishing, backup and recovery much easier!
The easiest way to write new code is to copy and edit existing code. The only problem is you might end up with a working program and no idea how you got there. Thats where I am right now with JavaScript from Netscape and NetImpact Dynamo from the Watcom subsidiary of Sybase.
Dynamo is Watcoms first contribution to the NetImpact family of internet-related products coming from Sybase. It started shipping in October as part of Sybase SQL Anywhere Professional 5.5.
NetImpact Dynamo lets you write database update applications that run on the web server instead of the client or browser side of the internet connection. You code the application as a combination of HTML and Dynamo Script, and you use the SQL Central database administration utility to store all the code in a SQL Anywhere 5.5 database as shown in Figure 1.
When your program runs, the application server portion of NetImpact Dynamo executes the Dynamo scripts to create more HTML code before shipping it all off to the client. This process usually includes database I/O, and when interactive input is received back from the client yet more Dynamo Script code is executed to process the users request.
A major component of NetImpact Dynamo is an application server which attaches to the CGI, ISAPI or NSAPI-compatible web server of your choice. It also comes with a Personal Web Server for testing applications, and includes several major enhancements to SQL Central and the SQL Anywhere database server to support web sites. The servers and development tools only run on Windows 95 or NT but there is no such restriction on deployment: All vestiges of Dynamo Script are removed from your web pages before they leave the server so any operating system and browser can be used on the client.
JavaScript is an interpreted language that looks a bit like Java but is a whole lot easier to learn and use. JavaScript is important to NetImpact Dynamo because it forms the foundation for Dynamo Script, just like BASIC is the foundation for PowerBuilders PowerScript. In other words, PowerScript is BASIC-like while Dynamo Script is JavaScript-like, and JavaScript is in turn Java-like.
If you count 60 days as being one Internet Year then JavaScript was developed many years ago by Sun and Netscape and introduced in Netscape Navigator Version 2. The latest version is JavaScript 1.1 supported by Navigator 3. You can code JavaScript to run on the client side, or on the server side as part of Netscapes LiveWire product line and now Sybases NetImpact Dynamo.
As part of Microsofts Lets Catch Up Slowly strategy, JavaScript is also available as JScript in Internet Explorer Version 3. JScript seems to be a partial copy of the older version of JavaScript, with some annoying differences that should eventually disappear if Microsoft and Netscape follow through with their promise to define a standard JavaScript.
The future looks bright for JavaScript. Its popularity is increasing, and not just for displaying sophomoric messages in scrolling status bars. It provides an easy way to partition your application between the client and the server without making the leap into Java.
If you believe the bumper sticker Strong Typing is for Programmers with Weak Minds then JavaScript is the language for you. Unlike Java, JavaScript and Dynamo Script variables dont have to be declared ahead of time and they dont have fixed data types at execution time. In other words, x = 5 and x = Hello both work and old dBase programmers should feel right at home.
JavaScript and Dynamo Script share some other big differences from Java: Your script is interspersed with HTML rather than held in separate applets, it is dynamically interpreted rather than compiled ahead of time, and object references are resolved at run time rather than compile time.
JavaScript is called object-based rather than object oriented because it lets you use and extend built-in objects but doesnt let you declare or inherit from new classes. Both Java and Dynamo Script, on the other hand, let you create new classes and fully indulge in the Big Three of object orientation: encapsulation, inheritance and polymorphism.
Nevertheless, Dynamo Script looks more like JavaScript than Java. This resemblance is more than academic because the Sybase documentation concentrates on facilities unique to NetImpact Dynamo. The little Dynamo booklet barely fills 100 pages, leaving you on your own to learn about the features shared between Dynamo Script and JavaScript. This stands in stark contrast with the thousand-plus pages in the SQL Anywhere 5.5 database manuals. Fortunately, you can find all you need on the web itself. Figure 2 shows where to get more information about the Netscape and Microsoft implementations of JavaScript.
JavaScript 1.0 Specifications from Netscape: http://home.netscape.com/eng/mozilla/Gold/handbook/javascript/index.html New Features in JavaScript 1.1: http://home.netscape.com/eng/mozilla/3.0/handbook/javascript/index.html JavaScript Articles in NetscapeWorld Magazine: http://www.netscapeworld.com/netscapeworld JavaScript Articles in JavaWorld Magazine: http://www.javaworld.com JScript from Microsoft: http://www.microsoft.com/jscript/ JScript Documentation Download: http://www.microsoft.com/jscript/us/download/jsdoc.exe |
Figure 3 shows a simple JavaScript example. Lines 6 to 13 contain the script code to display todays date. Line 8 creates a new instance of the Date object in a variable called today and initializes it by default with the current date and time. Line 9 displays todays date using the writeln method of the built-in object called document. The writeln function sends text to the HTML output stream, making it one of the most heavily used functions in both JavaScript and Dynamo Script.
1 <HTML> 2 <TITLE>A JavaScript Demonstration</TITLE> 3 <BODY> 4 <H2>A JavaScript Demonstration</H2> 5 6 <SCRIPT LANGUAGE="JavaScript"> 7 <!-- 8 today = new Date(); 9 document.writeln 10 ( "<P>JavaScript Date: " 11 + today.toLocaleString() ); 12 //--> 13 </SCRIPT> 14 15 </BODY> 16 </HTML> |
While Figure 3 shows how JavaScript can be added to an HTML document by using a special tag, Figure 5 shows how Dynamo Script uses three new tags called SCRIPT, SQL and formatting. The page starts with the usual HTML on lines 1 to 4 followed by the JavaScript from before on lines 6 through 13.
The special SCRIPT tag on line 15 begins the section of Dynamo Script code which ends on line 20. The statements in this section work exactly the same as the JavaScript code except they are executed on the server instead of at the client.
1 <HTML> 2 <TITLE>A Dynamo Demonstration</TITLE> 3 <BODY BGCOLOR="#FFFFFF"> 4 <H2>A Dynamo Demonstration</H2> 5 6 <SCRIPT LANGUAGE="JavaScript"> 7 <!-- 8 today = new Date(); 9 document.writeln 10 ( "<P>JavaScript Date: " 11 + today.toLocaleString() ); 12 //--> 13 </SCRIPT> 14 15 <!--SCRIPT 16 today = new Date(); 17 document.writeln 18 ( "<P>Dynamo Date: " 19 + today.toLocaleString() ); 20 --> 21 22 <!--SQL 23 SELECT status_code, 24 sort_order, 25 DateFormat ( last_updated_at, 26 'yyyy mm dd hh:mm' ) 27 FROM activity_status 28 ORDER BY sort_order 29 --> 30 31 <P> 32 <TABLE BORDER> 33 <TR> 34 <TH>Status Code</TH> 35 <TH>Sort Order</TH> 36 <TH>Last Updated</TH> 37 </TR> 38 39 <!--formatting--> 40 <TR> 41 <TD><!--data--></TD> 42 <TD><!--data--></TD> 43 <TD><!--data--></TD> 44 </TR> 45 <!--/formatting--> 46 47 </TABLE> 48 49 </BODY> 50 </HTML> |
Unlike embedded SELECTs in PowerScript the Dynamo SELECT on line 23 returns a result set. The formatting tag on line 39 tells the server what to do with each row: The three data tags are placeholders for the three columns, and the code between lines 40 and 44 causes a new HTML table row with three columns to be created for each row in the result set.
The rest of Figure 5 consists of ordinary HTML tags that start the table definition (lines 31 through 37), end the table (line 47) and close the whole document (lines 49 and 50). Figure 6 shows the result in Netscape Navigator.
Figure 7 shows that all the Dynamo Script code was turned into HTML before it reached the browser. This explains why the two times displayed in Figure 6 are one second apart: The Dynamo date was calculated on the server while the JavaScript date wasnt calculated until the HTML was displayed by the client. To see a window like Figure 7 on your computer, use View - Document Source in Navigator or View - Source in Internet Explorer.
The whole script in Figure 5 was initially created by the SQL Central wizard shown in Figure 8. The script was modified slightly for publication but almost all the ugly <tags> were filled in by the wizard.
Old dBase programmers have another reason to feel at home writing JavaScript and Dynamo programs. Thats because dBase programs often contain macros that produce more dBase code as output. In other words, programs that write programs. And thats what you have to do for World Wide Web applications: Write programs that produce HTML, and sometimes even JavaScript, as output.
But wait, theres more! Unlike C++ or even PowerBuilder programs, JavaScript and Dynamo applications are interpreted in the truest sense of the word. Both languages contain the eval() function which can evaluate the expression or execute the statements contained in a string argument. This facility is not to be taken lightly: It can be used to create elegant and sophisticated solutions to solve some very difficult problems, and it can also be used to create code that is incredibly difficult to understand and maintain.
Even if you dont use eval() there is still opportunity for confusion. The simplest Dynamo application always involves at least two languages, Dynamo Script and HTML. If you add some client-side JavaScript then youre working with a third language, and maybe your code in one language (Dynamo, JavaScript) is generating code in another (JavaScript, HTML). Even though Dynamo Script and JavaScript look very similar, they have many different features and theyre executed at different times on different platforms. This all means you sometimes find yourself asking these questions:
Is this HTML? Is it Dynamo Script? Or is it JavaScript?
Is this statement just doing something simple or is it generating code in another language?
Is this Dynamo Script statement generating HTML? Or JavaScript?
Is this JavaScript statement generating HTML?
Or is this a Dynamo Script statement generating JavaScript to generate HTML?
Or (gasp) is this Dynamo Script generating Dynamo Script to generate...
And thats when you run screaming from the room. Or if you persist, Figure 9 shows nine different kinds of HTML, Dynamo and JavaScript code, each in its own section labeled A through I. These sections progress in complexity and strangeness from simple HTML in Section A, through Dynamo Script generating JavaScript in Section E, all the way to self-generating JavaScript in Section I.
Each section is shown again in its final form in Figure 10. Where Figure 9 shows the original source code, Figure 10 shows the code as the browser sees it. The next few paragraphs describe each section and what happens to it along the way from Figure 9 to Figure 10 and how it produces the final output in Figures 11 and 12.
<HTML> <!-- (A) Simple HTML Code --> <HEAD> <TITLE>A Macro Programming Demonstration</TITLE> <!-- (B) Simple Dynamo Script Code --> <!--SCRIPT dynamoToday = new Date(); --> <!-- (C) Simple JavaScript Code --> <SCRIPT LANGUAGE="JavaScript"> <!-- javaScriptToday = new Date(); //--> </SCRIPT> <!-- ... more Simple HTML Code --> </HEAD> <BODY BGCOLOR="#FFFFFF"> <H2>A Macro Programming Demonstration</H2> <!-- (D) Dynamo Script to Generate HTML --> <!--SCRIPT document.writeln ( "<P>dynamoToday = " + dynamoToday.toLocaleString() ); --> <!-- (E) Dynamo Script to Generate JavaScript --> <!--SCRIPT javaScriptCode = "\<\!\-\- Code Generated by Example (E) \-\-\>\n" + "<SCRIPT LANGUAGE=\"JavaScript\">\n" + "\<\!\-\-\n" + "alert ( \"The Dynamo Document Name is '" + document.name + "'\" );\n" + "\/\/\-\->\n" + "</SCRIPT>\n"; document.writeln ( javaScriptCode ); --> <!-- (F) JavaScript to Generate HTML --> <SCRIPT LANGUAGE="JavaScript"> <!-- document.writeln ( "<P>javaScriptToday = " + javaScriptToday.toLocaleString() ); //--> </SCRIPT> <!-- (G) Dynamo to JavaScript to HTML --> <!--SCRIPT javaScriptCode = "\<\!\-\- Code Generated by (G) \-\-\>\n" + "<SCRIPT LANGUAGE=\"JavaScript\">\n" + "\<\!\-\-\n" + "document.writeln\n" + " ( \"<P>document.name = '" + document.name + "'<BR>\" );\n" + "document.writeln\n" + " ( \"<BR>document.referrer = '\"" + " + document.referrer + \"'\" );\n" + "\/\/\-\->\n" + "</SCRIPT>\n"; document.writeln ( javaScriptCode ); --> <!-- (H) Dynamo to Dynamo --> <!--SCRIPT expression = "Math.PI * 2"; document.writeln ( "<P>eval expression = " + eval ( expression ) ); --> <!-- (I) JavaScript to JavaScript --> <SCRIPT LANGUAGE="JavaScript"> <!-- eval ( "document.writeln " + " ( \"<P>eval document.referrer = '\"" + " + document.referrer + \"'\" );" ); //--> </SCRIPT> <!-- ... more Simple HTML Code --> </BODY> </HTML> |
Section B contains some straightforward Dynamo Script, and by straightforward I mean it doesnt generate any display text, HTML tags or JavaScript. In fact Section B doesnt appear in Figure 10 at all because it runs on the server and assigns a value to a variable that exists only on that server. In other words, NetImpact Dynamo removes Section B completely.
Section C in Figure 9 contains straightforward JavaScript code. It is passed unchanged to the browser as shown in Figure 10. This code is executed by the browser to assign a value to a client-side variable. Since it does not produce any display text or HTML it has no visible effect on Figures 11 or 12.
Section D contains Dynamo Script that runs on the server to create an HTML tag and one line of text. Figure 10 shows what Section D looks like after the server is finished with it, and the final display is shown in Figure 12.
Section E contains more Dynamo Script but this time it is generating code that can only be written in JavaScript: a call to alert(). This call displays the document.name property and since thats only available in Dynamo Script then a combination of both languages is required. Figure 10 shows that the value for document.name has been filled in, and the final result is shown in Figure 11.
At first glance the embedded JavaScript in Section E looks monstrously ugly because of all the backslash \ characters but the ideas quite simple. To prevent Dynamo from getting confused by special characters embedded within string literals, every one of them is preceded by the special escape character \. Some of these backslash characters might be unnecessary but its too hard to remember the rules. Its easier just to fill a huge saltshaker with backslash characters and sprinkle them throughout your strings. Its also easy to debug problems because your browser can show you the result from Figure 10.
Section F is like Section D but this time its JavaScript thats generating the HTML tag and display text. This code looks the same in Figures 9 and 10 because its up to the browser to process it.
If you think Section E is ugly then Section Gs gonna make you hurl. Here is Dynamo Script code that generates JavaScript, and when that code runs it generates HTML. On the other hand, if youve ever coded the tildes in a call to the PowerBuilder Modify() function then youre tough enough to handle Section G. Once again, some Dynamo-only code (document.name) is combined with JavaScript-only code (document.referrer) and the result is displayed via HTML instead of calling alert().
Section H shows that NetImpact Dynamo can indeed evaluate Dynamo Script created on the fly. Figure 9 shows a string literal containing Math.PI * 2 while Figure 10 shows that eval() has turned it into 6.2831.
Section I looks a lot like Section H except this time its JavaScript code thats calling eval(), and rather than a simple arithmetic expression it is a complete JavaScript statement embedded in a string. Figure 10 shows that unlike Section H, Section I is passed unchanged to the browser because this call to eval() is processed on the client side instead of on the server.
<HTML> <!-- (A) Simple HTML Code --> <HEAD> <TITLE>A Macro Programming Demonstration</TITLE> <!-- (B) Simple Dynamo Script Code --> <!-- (C) Simple JavaScript Code --> <SCRIPT LANGUAGE="JavaScript"> <!-- javaScriptToday = new Date(); //--> </SCRIPT> <!-- ... more Simple HTML Code --> </HEAD> <BODY BGCOLOR="#FFFFFF"> <H2>A Macro Programming Demonstration</H2> <!-- (D) Dynamo Script to Generate HTML --> <P>dynamoToday = 12/04/96 15:27:23 <!-- (E) Dynamo Script to Generate JavaScript --> <!-- Code Generated by Example (E) --> <SCRIPT LANGUAGE="JavaScript"> <!-- alert ( "The Dynamo Document Name is 'simpleMacroDemo.stm'" ); //--> </SCRIPT> <!-- (F) JavaScript to Generate HTML --> <SCRIPT LANGUAGE="JavaScript"> <!-- document.writeln ( "<P>javaScriptToday = " + javaScriptToday.toLocaleString() ); //--> </SCRIPT> <!-- (G) Dynamo to JavaScript to HTML --> <!-- Code Generated by (G) --> <SCRIPT LANGUAGE="JavaScript"> <!-- document.writeln ( "<P>document.name = 'simpleMacroDemo.stm'<BR>" ); document.writeln ( "<BR>document.referrer = '" + document.referrer + "'" ); //--> </SCRIPT> <!-- (H) Dynamo to Dynamo --> <P>eval expression = 6.28318530717959 <!-- (I) JavaScript to JavaScript --> <SCRIPT LANGUAGE="JavaScript"> <!-- eval ( "document.writeln " + " ( \"<P>eval document.referrer = '\"" + " + document.referrer + \"'\" );" ); //--> </SCRIPT> <!-- ... more Simple HTML Code --> </BODY> </HTML> |
All this talk of macro programming might seem out of place in an article entitled Getting Started, especially since the examples seem to be doing a lot of work for little benefit. After all, most applications dont need to calculate pi-times-two at all let alone do it dynamically via eval().
The examples in Figures 9 and 10 were kept trivial for a reason: To show the syntax of macro programming without the added complexity of real-world application logic. But now its time for a dose of real-world and a good place to start is the monotony of form-based HTML and JavaScript coding.
Figure 13 shows a very simple HTML form in action. There are seven text fields with titles, two buttons, and judging from the alert() box showing theres also JavaScript code that checks each input field to make sure its filled in. If youve ever worked with HTML forms then you know that even the simple ones are laborious to code and the addition of client-side validation logic makes it even more time-consuming.
The corresponding Dynamo Script is shown in Figure 14. Yes, theres more Dynamo Script behind the scenes but it was written once and reused. The code in Figure 14 is the only new code required, and it only takes 9 function calls to do it all.
<HTML> <TITLE>Test Field Macros</TITLE> <BODY BGCOLOR="#FFFFFF"> <H3>Test Field Macros</H3> <!--SCRIPT import defineForm.ssc; defineForm ( "testFields", "testFieldsConfirm.ssc" ); defineField ( "First Name", "firstName" ); defineField ( "Last Name", "lastName" ); defineField ( "Address Line 1", "address1" ); defineField ( "Address Line 2", "address2" ); defineField ( "Address Line 3", "address3" ); defineField ( "Zip/Postal Code", "postalCode" ); defineField ( "Phone", "phoneNumber" ); generateForm(); --> </BODY> </HTML> |
<HTML> <TITLE>Test Field Macros</TITLE> <BODY BGCOLOR="#FFFFFF"> <H3>Test Field Macros</H3> <SCRIPT LANGUAGE="JavaScript"> <!-- function testFieldsIsOK ( aForm ) { if ( aForm.firstName.value.length == 0 ) { alert ( "\nPlease fill in the First Name field." ); aForm.firstName.focus(); return ( false ); } if ( aForm.lastName.value.length == 0 ) { alert ( "\nPlease fill in the Last Name field." ); aForm.lastName.focus(); return ( false ); } if ( aForm.address1.value.length == 0 ) { alert ( "\nPlease fill in the Address Line 1 field." ); aForm.address1.focus(); return ( false ); } if ( aForm.address2.value.length == 0 ) { alert ( "\nPlease fill in the Address Line 2 field." ); aForm.address2.focus(); return ( false ); } if ( aForm.address3.value.length == 0 ) { alert ( "\nPlease fill in the Address Line 3 field." ); aForm.address3.focus(); return ( false ); } if ( aForm.postalCode.value.length == 0 ) { alert ( "\nPlease fill in the Zip/Postal Code field." ); aForm.postalCode.focus(); return ( false ); } if ( aForm.phoneNumber.value.length == 0 ) { alert ( "\nPlease fill in the Phone field." ); aForm.phoneNumber.focus(); return ( false ); } return ( true ); } function submittestFields ( aForm ) { if ( ! testFieldsIsOK ( aForm ) ) return; document.testFields.submit(); return; } //--> </SCRIPT> <FORM NAME="testFields" ACTION="testFieldsConfirm.ssc" METHOD="GET"> First Name: <INPUT NAME="firstName" TYPE="text"><BR> Last Name: <INPUT NAME="lastName" TYPE="text"><BR> Address Line 1: <INPUT NAME="address1" TYPE="text"><BR> Address Line 2: <INPUT NAME="address2" TYPE="text"><BR> Address Line 3: <INPUT NAME="address3" TYPE="text"><BR> Zip/Postal Code: <INPUT NAME="postalCode" TYPE="text"><BR> Phone: <INPUT NAME="phoneNumber" TYPE="text"><BR> <INPUT TYPE="button" NAME="Submit" VALUE="Submit" onClick="submittestFields ( this.form )"> <INPUT TYPE="reset" VALUE="Clear Fields"> </FORM> <SCRIPT LANGUAGE="JavaScript"> <!-- document.testFields.firstName.focus(); //--> </SCRIPT> </BODY> </HTML> |
If you didn't believe that coding HTML forms was boring then Figure 15 should convince you. And remember, this is a simple form, many are much harder. So how was it generated? Figure 16 tells the story: It contains the code called from Figure 14 to produce Figure 15.
<!--SCRIPT defineForm.ssc var formName; var formAction; var fieldUpperBound; var fieldTitle; var fieldName; var i; function defineForm ( aFormName, aFormAction ) { // Start saving data about a new form. formName = aFormName; formAction = aFormAction; fieldUpperBound = -1; } function defineField ( aFieldTitle, aFieldName ) { // Save data about another field in the current form. fieldUpperBound++; fieldTitle [ fieldUpperBound ] = aFieldTitle; fieldName [ fieldUpperBound ] = aFieldName; } function generateForm() { // Write a JavaScript header. document.writeln ( "<SCRIPT LANGUAGE=\"JavaScript\">\n" + "\<\!\-\-" ); // Write the <formName>IsOK function header. document.writeln ( "function " + formName + "IsOK ( aForm ) {" ); // Write the individual field check logic. for ( i = 0; i <= fieldUpperBound; i++ ) { document.writeln ( " if ( aForm." + fieldName [ i ] + ".value.length == 0 ) {\n" + " alert ( \"\\nPlease fill in the " + fieldTitle [ i ] + " field.\" );\n" + " aForm." + fieldName [ i ] + ".focus();\n" + " return ( false );\n" + " }" ); } // Write the <formName>IsOK function trailer. document.writeln ( " return ( true );\n" + "}\n" ); // Write the submit<formName> function. document.writeln ( "function submit" + formName + " ( aForm ) {\n" + " if ( ! " + formName + "IsOK ( aForm ) ) return;\n" + " document." + formName + ".submit();\n" + " return;\n" + "}\n" ); // Write a JavaScript trailer. document.writeln ( "\/\/\-\->\n" + "</SCRIPT>\n" ); // Write the HTML form header tag. document.writeln ( "\<FORM NAME=\"" + formName + "\" ACTION=\"" + formAction + "\" METHOD=\"GET\"\>" ); // Write the individual HTML field tags. for ( i = 0; i <= fieldUpperBound; i++ ) { document.writeln ( fieldTitle [ i ] + ": \<INPUT NAME=\"" + fieldName [ i ] + "\" TYPE=\"text\"\>\<BR\>" ); } // Write the HTML submit button tag. document.writeln ( "<INPUT TYPE=\"button\" NAME=\"Submit\"" + " VALUE=\"Submit\"" + " onClick=\"submit" + formName + " ( this.form )\"\>" ); // Write the HTML reset button tag. document.writeln ( "\<INPUT TYPE=\"reset\"" + " VALUE=\"Clear Fields\"\>" ); // Write the HTML form trailer tag. document.writeln ( "\<\/FORM\>\n" ); // Write a JavaScript header. document.writeln ( "<SCRIPT LANGUAGE=\"JavaScript\">\n" + "\<\!\-\-" ); // Write the JavaScript code to position the cursor. document.writeln ( "document." + formName + "." + fieldName [ 0 ] + ".focus();" ); // Write a JavaScript trailer. document.writeln ( "\/\/\-\->\n" + "</SCRIPT>\n" ); } --> |
Except for all the strange strings and escape characters the code in Figure 16 is fairly straightforward. That's good, because a real form generator should give the programmer more control over design and layout. It should allow for check boxes, radio buttons and other kinds of fields as well as text input, and it should permit different fields to have different kinds of validation checks. And, of course, the world is crying out for the HTML equivalent of PowerBuilder's DropDownDataWindow.
[Home] | [Back to Tip 73] | [Forward to Tip 75] | [Archives] |
|
[mail to: bcarter@bcarter.com] |