25.01.2015 Views

Using Zen - InterSystems Documentation

Using Zen - InterSystems Documentation

Using Zen - InterSystems Documentation

SHOW MORE
SHOW LESS

Create successful ePaper yourself

Turn your PDF publications into a flip-book with our unique Google optimized e-Paper software.

<strong>Using</strong> <strong>Zen</strong><br />

Version 2007.1<br />

04 June 2007<br />

<strong>InterSystems</strong> Corporation 1 Memorial Drive Cambridge MA 02142 www.intersystems.com


<strong>Using</strong> <strong>Zen</strong><br />

Caché Version 2007.1 04 June 2007<br />

Copyright © 2007 <strong>InterSystems</strong> Corporation<br />

All rights reserved.<br />

This book was assembled and formatted in Adobe Page Description Format (PDF) using tools and information from<br />

the following sources: Sun Microsystems, RenderX, Inc., Adobe Systems, and the World Wide Web Consortium at<br />

www.w3c.org. The primary document development tools were special-purpose XML-processing applications built<br />

by <strong>InterSystems</strong> using Caché and Java.<br />

and<br />

Caché WEBLINK, Distributed Cache Protocol, M/SQL, N/NET, and M/PACT are registered trademarks of <strong>InterSystems</strong><br />

Corporation.<br />

and<br />

<strong>InterSystems</strong> Jalapeño Technology, Enterprise Cache Protocol, ECP, and <strong>InterSystems</strong> <strong>Zen</strong> are trademarks of<br />

<strong>InterSystems</strong> Corporation.<br />

All other brand or product names used herein are trademarks or registered trademarks of their respective companies<br />

or organizations.<br />

This document contains trade secret and confidential information which is the property of <strong>InterSystems</strong> Corporation,<br />

One Memorial Drive, Cambridge, MA 02142, or its affiliates, and is furnished for the sole purpose of the operation<br />

and maintenance of the products of <strong>InterSystems</strong> Corporation. No part of this publication is to be used for any other<br />

purpose, and this publication is not to be reproduced, copied, disclosed, transmitted, stored in a retrieval system or<br />

translated into any human or computer language, in any form, by any means, in whole or in part, without the express<br />

prior written consent of <strong>InterSystems</strong> Corporation.<br />

The copying, use and disposition of this document and the software programs described herein is prohibited except<br />

to the limited extent set forth in the standard software license agreement(s) of <strong>InterSystems</strong> Corporation covering<br />

such programs and related documentation. <strong>InterSystems</strong> Corporation makes no representations and warranties<br />

concerning such software programs other than those set forth in such standard software license agreement(s). In<br />

addition, the liability of <strong>InterSystems</strong> Corporation for any losses or damages relating to or arising out of the use of<br />

such software programs is limited in the manner set forth in such standard software license agreement(s).<br />

THE FOREGOING IS A GENERAL SUMMARY OF THE RESTRICTIONS AND LIMITATIONS IMPOSED BY<br />

INTERSYSTEMS CORPORATION ON THE USE OF, AND LIABILITY ARISING FROM, ITS COMPUTER<br />

SOFTWARE. FOR COMPLETE INFORMATION REFERENCE SHOULD BE MADE TO THE STANDARD SOFTWARE<br />

LICENSE AGREEMENT(S) OF INTERSYSTEMS CORPORATION, COPIES OF WHICH WILL BE MADE AVAILABLE<br />

UPON REQUEST.<br />

<strong>InterSystems</strong> Corporation disclaims responsibility for errors which may appear in this document, and it reserves the<br />

right, in its sole discretion and without notice, to make substitutions and modifications in the products and practices<br />

described in this document.<br />

For Support questions about any <strong>InterSystems</strong> products, contact:<br />

<strong>InterSystems</strong> Worldwide Customer Support<br />

Tel: +1 617 621-0700<br />

Fax: +1 617 374-9391<br />

Email: support@<strong>InterSystems</strong>.com


Table of Contents<br />

Preface ................................................................................................................................................ 1<br />

1 Introducing <strong>Zen</strong> .............................................................................................................................. 3<br />

1.1 The <strong>Zen</strong> Demo ....................................................................................................................... 3<br />

1.2 Supported Browsers ............................................................................................................... 4<br />

1.3 Benefits of <strong>Zen</strong> ....................................................................................................................... 4<br />

1.4 Background Reading .............................................................................................................. 5<br />

2 <strong>Zen</strong> Tutorial .................................................................................................................................... 7<br />

2.1 Hello World ............................................................................................................................ 7<br />

2.2 Creating a <strong>Zen</strong> Application .................................................................................................... 9<br />

2.3 Creating a <strong>Zen</strong> Page ............................................................................................................. 10<br />

2.3.1 Step 1: New Page Wizard .......................................................................................... 10<br />

2.3.2 Step 2: XData Contents Block ................................................................................... 13<br />

2.3.3 Step 3: Client-Side Method ....................................................................................... 15<br />

2.3.4 Step 4: Viewing the HTML Output ............................................................................ 17<br />

2.3.5 Step 5: Server-Side Method ....................................................................................... 17<br />

2.4 Creating a <strong>Zen</strong> Report .......................................................................................................... 20<br />

2.5 <strong>Zen</strong> Naming Conventions .................................................................................................... 22<br />

2.6 <strong>Zen</strong> Sample Applications ..................................................................................................... 23<br />

2.7 <strong>Zen</strong> Wizards ......................................................................................................................... 24<br />

3 <strong>Zen</strong> Client and Server .................................................................................................................. 25<br />

3.1 <strong>Zen</strong> and Caché Server Pages ................................................................................................ 25<br />

3.2 <strong>Zen</strong> Pages at Runtime .......................................................................................................... 27<br />

4 <strong>Zen</strong> Application Concepts ............................................................................................................ 31<br />

4.1 <strong>Zen</strong> Applications .................................................................................................................. 31<br />

4.2 <strong>Zen</strong> Pages ............................................................................................................................. 33<br />

4.3 <strong>Zen</strong> Components .................................................................................................................. 34<br />

5 <strong>Zen</strong> Component Concepts ........................................................................................................... 37<br />

5.1 Page ...................................................................................................................................... 38<br />

5.2 Layout .................................................................................................................................. 39<br />

5.3 Style ..................................................................................................................................... 40<br />

5.4 Behavior ............................................................................................................................... 40<br />

5.5 Customization ...................................................................................................................... 41<br />

6 <strong>Zen</strong> Layout .................................................................................................................................... 43<br />

6.1 XData Contents .................................................................................................................... 44<br />

<strong>Using</strong> <strong>Zen</strong><br />

iii


6.2 Pages .................................................................................................................................... 45<br />

6.3 Titles ..................................................................................................................................... 45<br />

6.3.1 Simple Titles .............................................................................................................. 46<br />

6.3.2 Complex Titles ........................................................................................................... 47<br />

6.4 Groups .................................................................................................................................. 48<br />

6.4.1 Layout Strategy .......................................................................................................... 48<br />

6.4.2 Simple Group Components ........................................................................................ 48<br />

6.4.3 Menu Components ..................................................................................................... 49<br />

6.4.4 Complex Group Components .................................................................................... 50<br />

6.4.5 Group Layout and Style Attributes ............................................................................ 50<br />

6.5 Template Pages ..................................................................................................................... 53<br />

6.6 Panes .................................................................................................................................... 54<br />

6.7 Generated HTML ................................................................................................................. 56<br />

7 <strong>Zen</strong> Style ........................................................................................................................................ 57<br />

7.1 Component Style Attributes ................................................................................................. 57<br />

7.2 Enclosing Element ..................................................................................................... 60<br />

7.3 XData Style .......................................................................................................................... 61<br />

7.4 Inheritance of Styles ............................................................................................................ 62<br />

7.5 Cascade of Styles ................................................................................................................. 63<br />

7.6 Overriding Built-in Styles .................................................................................................... 65<br />

7.6.1 Finding the CSS Style Name ..................................................................................... 66<br />

7.6.2 Overriding a CSS Style Rule ..................................................................................... 67<br />

7.7 Applying New Styles ........................................................................................................... 69<br />

8 <strong>Zen</strong> Tables ..................................................................................................................................... 71<br />

8.1 .......................................................................................................................... 72<br />

8.2 Data Sources ........................................................................................................................ 73<br />

8.2.1 Specifying an SQL Query .......................................................................................... 74<br />

8.2.2 Generating an SQL Query ......................................................................................... 74<br />

8.2.3 Referencing a Class Query ........................................................................................ 76<br />

8.2.4 <strong>Using</strong> a Callback Method .......................................................................................... 76<br />

8.3 Query Parameters ................................................................................................................. 80<br />

8.4 Table Columns ..................................................................................................................... 81<br />

8.5 Table Style ............................................................................................................................ 83<br />

8.6 Conditional Style for Rows or Cells .................................................................................... 85<br />

8.7 Snapshot Mode ..................................................................................................................... 87<br />

8.7.1 Fetching Data From the Server .................................................................................. 88<br />

8.7.2 Navigating Snapshot Tables ....................................................................................... 89<br />

8.8 Column Filters ..................................................................................................................... 90<br />

8.9 Column Links ....................................................................................................................... 93<br />

8.10 User Interactions ................................................................................................................ 95<br />

iv<br />

<strong>Using</strong> <strong>Zen</strong>


8.10.1 Navigation Buttons .................................................................................................. 95<br />

8.10.2 Navigation Keys ....................................................................................................... 95<br />

8.10.3 Sorting Tables .......................................................................................................... 96<br />

8.10.4 Selecting Rows and Columns .................................................................................. 96<br />

8.11 Table Refresh ..................................................................................................................... 98<br />

8.12 Table Touchups .................................................................................................................. 99<br />

9 <strong>Zen</strong> and SVG ............................................................................................................................... 101<br />

9.1 SVG Component Layout .................................................................................................... 102<br />

9.1.1 ............................................................................................................. 102<br />

9.1.2 ............................................................................................................. 109<br />

9.1.3 ............................................................................................................ 109<br />

9.1.4 ....................................................................................................................... 109<br />

9.2 SVG Component Attributes ............................................................................................... 110<br />

9.3 Meters ................................................................................................................................ 112<br />

9.3.1 Providing Data for Meters ....................................................................................... 112<br />

9.3.2 Meter Attributes ....................................................................................................... 113<br />

9.3.3 ............................................................................................................ 115<br />

9.3.4 ..................................................................................................... 116<br />

9.3.5 ................................................................................................................ 117<br />

9.3.6 .................................................................................................................. 119<br />

9.3.7 ......................................................................................................... 119<br />

9.3.8 .......................................................................................................... 121<br />

9.4 Charts ................................................................................................................................. 121<br />

9.5 .............................................................................................................. 122<br />

9.6 .................................................................................................................... 125<br />

10 <strong>Zen</strong> Charts ................................................................................................................................ 127<br />

10.1 Types of Chart .................................................................................................................. 129<br />

10.1.1 Line Charts ............................................................................................................. 129<br />

10.1.2 Bar Charts .............................................................................................................. 131<br />

10.1.3 Difference Charts ................................................................................................... 133<br />

10.1.4 High/Low Charts .................................................................................................... 134<br />

10.1.5 Scatter Diagrams .................................................................................................... 136<br />

10.1.6 Pie Charts ............................................................................................................... 137<br />

10.2 Providing Data for Charts ................................................................................................ 141<br />

10.2.1 Limiting the Data Set ............................................................................................. 142<br />

10.2.2 <strong>Using</strong> a JavaScript Method .................................................................................... 143<br />

10.2.3 <strong>Using</strong> a Data Controller ......................................................................................... 144<br />

10.3 Chart Attributes ................................................................................................................ 145<br />

10.3.1 Layout and Style .................................................................................................... 145<br />

10.3.2 Plot Area ................................................................................................................ 146<br />

<strong>Using</strong> <strong>Zen</strong><br />

v


10.3.3 Markers .................................................................................................................. 148<br />

10.3.4 Legends .................................................................................................................. 149<br />

10.3.5 Titles ...................................................................................................................... 150<br />

10.3.6 User Selections ...................................................................................................... 151<br />

10.4 Chart Axes ........................................................................................................................ 152<br />

11 <strong>Zen</strong> Forms ................................................................................................................................. 155<br />

11.1 Forms and Controls .......................................................................................................... 155<br />

11.2 User Interactions .............................................................................................................. 158<br />

11.3 Defining a Form ............................................................................................................... 158<br />

11.4 Providing Values for a Form ............................................................................................ 161<br />

11.5 Detecting Modifications to the Form .............................................................................. 162<br />

11.6 Validating a Form ............................................................................................................. 162<br />

11.7 Errors and Invalid Values ................................................................................................. 163<br />

11.8 Processing a Form Submit ............................................................................................... 164<br />

11.9 User Login Forms ............................................................................................................ 166<br />

11.10 Dynamic Forms .............................................................................................................. 166<br />

12 <strong>Zen</strong> Controls ............................................................................................................................. 169<br />

12.1 Control Attributes ............................................................................................................. 170<br />

12.2 Control Methods .............................................................................................................. 173<br />

12.3 Buttons ............................................................................................................................. 174<br />

12.3.1 ................................................................................................................. 174<br />

12.3.2 ................................................................................................................. 174<br />

12.3.3 ................................................................................................................ 175<br />

12.4 Text ................................................................................................................................... 176<br />

12.4.1 ................................................................................................................... 176<br />

12.4.2 ..................................................................................................................... 176<br />

12.4.3 .............................................................................................................. 177<br />

12.4.4 ............................................................................................................ 177<br />

12.5 Simple Choices ................................................................................................................ 178<br />

12.5.1 ............................................................................................................ 178<br />

12.5.2 .......................................................................................................... 179<br />

12.5.3 ........................................................................................................ 180<br />

12.5.4 .............................................................................................................. 180<br />

12.5.5 ........................................................................................................ 183<br />

12.6 Lists .................................................................................................................................. 184<br />

12.6.1 .................................................................................................................. 185<br />

12.6.2 ............................................................................................................... 188<br />

12.6.3 ....................................................................................................... 189<br />

12.6.4 .......................................................................................................... 191<br />

12.6.5 ........................................................................................................ 195<br />

vi<br />

<strong>Using</strong> <strong>Zen</strong>


12.7 Calendars .......................................................................................................................... 202<br />

12.7.1 ............................................................................................................. 202<br />

12.7.2 ............................................................................................................. 205<br />

12.8 Hidden Items .................................................................................................................... 207<br />

12.9 Spreadsheet ...................................................................................................................... 207<br />

12.9.1 Data Set ............................................................................................. 208<br />

12.9.2 Methods ............................................................................................. 210<br />

12.9.3 ............................................................................................................. 212<br />

12.9.4 ........................................................................................................ 213<br />

12.9.5 Attributes ........................................................................................... 215<br />

13 Model View Controller ............................................................................................................. 219<br />

13.1 Architecture ...................................................................................................................... 219<br />

13.1.1 Data Model ............................................................................................................ 220<br />

13.1.2 Data Controller ...................................................................................................... 222<br />

13.1.3 Data View ............................................................................................................... 225<br />

13.2 Constructing a Model ....................................................................................................... 228<br />

13.2.1 Step 1: Type of Model ............................................................................................ 228<br />

13.2.2 Step 2: Object Data Model .................................................................................... 229<br />

13.3 Binding a to an Object Data Model .................................................................... 230<br />

13.3.1 Step 1: Data Controller .......................................................................................... 231<br />

13.3.2 Step 2: Data View .................................................................................................. 231<br />

13.3.3 Step 3: Initial Results ............................................................................................. 232<br />

13.3.4 Step 4: Saving the Form ......................................................................................... 232<br />

13.4 Adding Behavior to the ....................................................................................... 234<br />

13.4.1 Step 1: Opening a New Record .............................................................................. 234<br />

13.4.2 Step 2: Creating and Deleting Records .................................................................. 236<br />

13.5 with an Object Data Model ........................................................................ 238<br />

13.5.1 Step 1: is Easy .................................................................................. 238<br />

13.5.2 Step 2: Converting to ....................................................................... 239<br />

13.5.3 Step 3: Automatic Control Selection ..................................................................... 241<br />

13.6 with an Adaptor Data Model ...................................................................... 244<br />

13.6.1 Step 1: Generating the Form .................................................................................. 245<br />

13.6.2 Step 2: Property Parameters ................................................................................... 246<br />

13.6.3 Step 3: Adding Behavior to the ........................................................ 247<br />

13.6.4 Step 4: Virtual Properties ....................................................................................... 249<br />

13.7 Data Model Classes .......................................................................................................... 251<br />

13.7.1 Data Model Class Properties ................................................................................. 252<br />

13.7.2 Data Model Class Parameters ................................................................................ 252<br />

13.7.3 Data Model Property Parameters ........................................................................... 253<br />

13.7.4 Object Data Model Callback Methods ................................................................... 254<br />

<strong>Using</strong> <strong>Zen</strong><br />

vii


13.7.5 Virtual Properties ................................................................................................... 256<br />

13.7.6 Controller Actions .................................................................................................. 258<br />

13.7.7 Data Model Series .................................................................................................. 258<br />

13.7.8 Custom Data Model Classes .................................................................................. 260<br />

14 Navigation Components ........................................................................................................... 261<br />

14.1 Links ................................................................................................................................ 263<br />

14.1.1 ..................................................................................................................... 263<br />

14.1.2 .......................................................................................................... 265<br />

14.1.3 ........................................................................................................ 266<br />

14.2 Menus ............................................................................................................................... 267<br />

14.2.1 ........................................................................................................... 268<br />

14.2.2 , , and ........................................................................ 270<br />

14.2.3 ................................................................................................... 271<br />

14.3 Tabs .................................................................................................................................. 271<br />

14.3.1 ............................................................................................................ 272<br />

14.3.2 ..................................................................................................... 275<br />

14.3.3 ...................................................................................................................... 278<br />

14.4 Expanding Group ............................................................................................................. 279<br />

15 Popup Windows and Dialogs ................................................................................................... 285<br />

15.1 Modal Groups .................................................................................................................. 285<br />

15.1.1 Static Modal Groups .............................................................................................. 286<br />

15.1.2 Dynamic Modal Groups ........................................................................................ 288<br />

15.1.3 Built-in Modal Groups ........................................................................................... 291<br />

15.1.4 The show Method .................................................................................................. 295<br />

15.1.5 Attributes ...................................................................................... 296<br />

15.2 Popup Windows ............................................................................................................... 298<br />

15.3 Dialogs ............................................................................................................................. 299<br />

15.3.1 File Selection Dialog Window ............................................................................... 300<br />

15.3.2 Color Selection Dialog Window ............................................................................ 300<br />

15.3.3 Creating a Dialog Window ..................................................................................... 301<br />

15.3.4 Creating a Dialog Window Template ..................................................................... 302<br />

16 Other <strong>Zen</strong> Components ........................................................................................................... 305<br />

16.1 HTML Content ................................................................................................................. 305<br />

16.2 Framed Content ................................................................................................................ 307<br />

16.3 Page Timer ....................................................................................................................... 308<br />

16.4 Field Sets .......................................................................................................................... 309<br />

16.5 Color Selector .................................................................................................................. 311<br />

16.6 Repeating Group .............................................................................................................. 313<br />

16.7 Dynamic Tree ................................................................................................................... 316<br />

viii<br />

<strong>Using</strong> <strong>Zen</strong>


16.7.1 Defining a Tree <strong>Using</strong> a Global ............................................................................. 316<br />

16.7.2 Defining a Tree <strong>Using</strong> a Callback .......................................................................... 317<br />

16.7.3 Attributes ........................................................................................... 320<br />

16.8 Dynamic View .................................................................................................................. 322<br />

16.8.1 Defining a View <strong>Using</strong> a Callback ......................................................................... 322<br />

16.8.2 Attributes .......................................................................................... 324<br />

17 Custom Components ................................................................................................................ 327<br />

17.1 Building Composite Components .................................................................................... 328<br />

17.1.1 The composite Property ......................................................................................... 330<br />

17.1.2 Composites and Panes ........................................................................................... 330<br />

17.2 Overriding Component Style ........................................................................................... 331<br />

17.3 Creating Custom Components ......................................................................................... 331<br />

17.3.1 Package and Namespace ........................................................................................ 333<br />

17.3.2 Base Class .............................................................................................................. 333<br />

17.3.3 <strong>Zen</strong> Component Wizard ........................................................................................ 334<br />

17.4 Custom Style .................................................................................................................... 334<br />

17.4.1 XData SVGStyle .................................................................................................... 336<br />

17.4.2 XData SVGDef ...................................................................................................... 336<br />

17.4.3 <strong>Zen</strong> Color Definitions ............................................................................................ 337<br />

17.5 Custom Properties ............................................................................................................ 337<br />

17.5.1 Naming Conventions ............................................................................................. 337<br />

17.5.2 XML Projection ..................................................................................................... 338<br />

17.5.3 setProperty Method ................................................................................................ 338<br />

17.5.4 Datatype Parameters .............................................................................................. 338<br />

17.5.5 Datatype Classes .................................................................................................... 340<br />

17.6 Custom Methods .............................................................................................................. 342<br />

17.6.1 %DrawHTML ........................................................................................................ 343<br />

17.6.2 Helper Methods for %DrawHTML ....................................................................... 344<br />

17.6.3 Identifying HTML Elements ................................................................................. 346<br />

17.6.4 Finding HTML Elements ....................................................................................... 347<br />

17.6.5 Setting HTML Attribute Values ............................................................................. 348<br />

17.6.6 Attaching Event Handlers to HTML Elements ..................................................... 348<br />

17.6.7 HTML for Dynamic Components ......................................................................... 350<br />

17.7 Examples of Custom Components ................................................................................... 351<br />

17.8 Creating Custom Meters .................................................................................................. 353<br />

17.8.1 Custom Meters in XData Contents ........................................................................ 354<br />

17.8.2 Odometer Meter Example ...................................................................................... 354<br />

17.8.3 Clock Meter Example ............................................................................................ 356<br />

18 <strong>Zen</strong> Application Programming ................................................................................................ 361<br />

18.1 <strong>Zen</strong> Classes as CSP Classes ............................................................................................. 361<br />

<strong>Using</strong> <strong>Zen</strong><br />

ix


18.2 <strong>Zen</strong> Application Classes ................................................................................................... 362<br />

18.3 <strong>Zen</strong> Page Classes .............................................................................................................. 363<br />

18.3.1 <strong>Zen</strong> Page Parameters .............................................................................................. 363<br />

18.3.2 <strong>Zen</strong> Special Variables ............................................................................................. 364<br />

18.3.3 <strong>Zen</strong> Runtime Expressions ...................................................................................... 368<br />

18.3.4 <strong>Zen</strong> Page Properties ............................................................................................... 371<br />

18.3.5 <strong>Zen</strong> Utility Methods .............................................................................................. 371<br />

18.3.6 Client-Side Functions and Variables ...................................................................... 372<br />

18.3.7 <strong>Zen</strong> Page URI Parameters ...................................................................................... 373<br />

18.3.8 <strong>Zen</strong> Page Event Handling ...................................................................................... 374<br />

18.4 <strong>Zen</strong> Properties on Client and Server ................................................................................ 374<br />

18.5 <strong>Zen</strong> Methods .................................................................................................................... 375<br />

18.5.1 Synchronous and Asynchronous Methods ............................................................. 376<br />

18.5.2 Server-Side Callback Methods .............................................................................. 376<br />

18.5.3 Server-Only Methods ............................................................................................. 378<br />

18.5.4 Type Conversion for Server-Side Methods ............................................................ 378<br />

18.5.5 Background Tasks on the Server ............................................................................ 379<br />

18.5.6 Client-Side Page Callback Methods ...................................................................... 379<br />

18.5.7 Client-Side Page Methods ..................................................................................... 380<br />

18.5.8 Client-Side Component Methods .......................................................................... 381<br />

18.6 <strong>Zen</strong> Page Contents ........................................................................................................... 381<br />

18.6.1 Defining Page Contents <strong>Using</strong> XML ..................................................................... 382<br />

18.6.2 XML Namespaces .................................................................................................. 382<br />

18.6.3 Defining Page Contents Programmatically ............................................................ 382<br />

18.6.4 <strong>Zen</strong> Layout Handler ............................................................................................... 383<br />

18.7 Sample Development Project ........................................................................................... 384<br />

19 <strong>Zen</strong> Security .............................................................................................................................. 391<br />

19.1 Controlling Access to Applications .................................................................................. 391<br />

19.2 Controlling Access to Pages ............................................................................................. 392<br />

19.3 Controlling Access to Components .................................................................................. 392<br />

20 <strong>Zen</strong> Localization ....................................................................................................................... 395<br />

20.1 CSP Localization ............................................................................................................. 395<br />

20.1.1 Localization Practices ............................................................................................ 395<br />

20.1.2 Message Dictionary ............................................................................................... 396<br />

20.1.3 $$$Text Macros ..................................................................................................... 396<br />

20.2 <strong>Zen</strong> Localization .............................................................................................................. 400<br />

20.2.1 Localization for Built-In Components ................................................................... 400<br />

20.2.2 Localization for Custom Components ................................................................... 401<br />

21 <strong>Zen</strong> Reports ............................................................................................................................... 403<br />

x<br />

<strong>Using</strong> <strong>Zen</strong>


21.1 Building a Report ............................................................................................................. 405<br />

21.2 <strong>Zen</strong> Report Parameters ..................................................................................................... 410<br />

21.3 XData ReportDefinition ................................................................................................... 413<br />

21.3.1 The %val Variable .................................................................................................. 414<br />

21.3.2 ................................................................................................................. 414<br />

21.3.3 .............................................................................................................. 414<br />

21.3.4 .............................................................................................................. 415<br />

21.3.5 ........................................................................................................... 415<br />

21.3.6 .................................................................................................................. 418<br />

21.4 XData ReportDisplay ....................................................................................................... 421<br />

21.4.1 Dimension and Size ............................................................................................... 423<br />

21.4.2 ................................................................................................................. 423<br />

21.4.3 ........................................................................................................... 424<br />

21.4.4 ......................................................................................................... 427<br />

21.4.5 .......................................................................................................... 427<br />

21.4.6 ................................................................................................................... 427<br />

21.5 Layout and Display Elements .......................................................................................... 427<br />

21.5.1 .................................................................................................................. 429<br />

21.5.2 .................................................................................................................. 429<br />

21.5.3 and .......................................................................................... 430<br />

21.5.4 ..................................................................................................................... 430<br />

21.5.5 .................................................................................................................... 431<br />

21.5.6 ..................................................................................................................... 432<br />

21.5.7 ...................................................................................................................... 433<br />

21.5.8 ......................................................................................................................... 434<br />

21.5.9 .......................................................................................................... 434<br />

21.5.10 ................................................................................................................. 434<br />

21.6 Charts in <strong>Zen</strong> Reports ...................................................................................................... 436<br />

21.7 Stylesheet Control Elements ............................................................................................ 437<br />

21.7.1 ........................................................................................................................ 437<br />

21.7.2 .................................................................................................................... 438<br />

21.7.3 ................................................................................................................... 438<br />

21.8 <strong>Zen</strong> Reports from a Web Browser .................................................................................... 438<br />

21.8.1 Sample XHTML Output ........................................................................................ 439<br />

21.8.2 Sample XML Data View ........................................................................................ 440<br />

21.9 Configuring <strong>Zen</strong> for PDF Output ..................................................................................... 440<br />

21.10 Troubleshooting <strong>Zen</strong> Reports ......................................................................................... 441<br />

21.11 <strong>Zen</strong> Reports from a Command Line .............................................................................. 443<br />

22 <strong>Zen</strong> Wizards .............................................................................................................................. 445<br />

22.1 New <strong>Zen</strong> Application Wizard ........................................................................................... 445<br />

<strong>Using</strong> <strong>Zen</strong><br />

xi


22.2 New <strong>Zen</strong> Component Wizard ........................................................................................... 446<br />

22.3 New <strong>Zen</strong> Page Wizard ...................................................................................................... 447<br />

22.4 New <strong>Zen</strong> Report Wizard ................................................................................................... 448<br />

22.5 Studio Assist ..................................................................................................................... 450<br />

22.6 <strong>Zen</strong> Chart Wizard ............................................................................................................. 450<br />

22.7 <strong>Zen</strong> Element Wizard ......................................................................................................... 452<br />

22.8 <strong>Zen</strong> Method Wizard ......................................................................................................... 453<br />

22.9 <strong>Zen</strong> Style Wizard .............................................................................................................. 455<br />

Index ............................................................................................................................................... 459<br />

xii<br />

<strong>Using</strong> <strong>Zen</strong>


List of Figures<br />

How to Access the Sample <strong>Zen</strong> Code in Studio ................................................................................ 24<br />

How Caché Server Pages Work ......................................................................................................... 26<br />

How <strong>Zen</strong> Pages Work ........................................................................................................................ 30<br />

<strong>Zen</strong> Application with Pages and Components ................................................................................... 32<br />

<strong>Zen</strong> Page Synchronized on Client and Server at Runtime ................................................................ 33<br />

Defining the Look and Feel of a <strong>Zen</strong> Page ........................................................................................ 34<br />

Use of Panes on a <strong>Zen</strong> Page .............................................................................................................. 55<br />

Cascade of Style Definitions ............................................................................................................. 65<br />

Layout Conventions for <strong>Zen</strong> Charts ................................................................................................ 128<br />

How <strong>Zen</strong> Plots Pie Charts by Item .................................................................................................. 139<br />

How <strong>Zen</strong> Plots Pie Charts by Series ................................................................................................ 140<br />

<strong>Zen</strong> Pie Chart from Both Items and Series ...................................................................................... 141<br />

Data Series Count and Size ............................................................................................................. 143<br />

Class Inheritance Among Form and Control Components .............................................................. 157<br />

Data Model for the Dynamic Grid Control ..................................................................................... 210<br />

Model View Controller Architecture ............................................................................................... 220<br />

Data Model Classes ......................................................................................................................... 221<br />

Data Controller and Data View Classes .......................................................................................... 223<br />

Data Model with Name-Value Pairs ................................................................................................ 258<br />

Data Model with Data Series .......................................................................................................... 259<br />

<strong>Zen</strong> Navigation Components ........................................................................................................... 263<br />

Base Classes for Custom Components ............................................................................................ 334<br />

Sample Log of <strong>Zen</strong> Events .............................................................................................................. 372<br />

How a <strong>Zen</strong> Report Class Produces a Report ................................................................................... 404<br />

XSL-FO to PDF Transformation Log ............................................................................................. 442<br />

XSL-FO Prior to PDF Rendering .................................................................................................... 443<br />

<strong>Using</strong> <strong>Zen</strong><br />

xiii


List of Tables<br />

Naming Conventions ......................................................................................................................... 22<br />

Component Concepts ........................................................................................................................ 38<br />

Group Layout and Style Attributes .................................................................................................... 51<br />

Component Style Attributes .............................................................................................................. 57<br />

Where and How to Override Built-in Styles ..................................................................................... 68<br />

QueryInfo Properties ......................................................................................................................... 78<br />

predicate Values ............................................................................................................ 86<br />

SVG Component Attributes ............................................................................................................ 110<br />

Meter Component Attributes ........................................................................................................... 113<br />

Chart Layout and Style Attributes ................................................................................................... 146<br />

Chart Axis Attributes ....................................................................................................................... 152<br />

Form Component Attributes ............................................................................................................ 158<br />

Form Submit Sequence ................................................................................................................... 165<br />

Control Component Attributes ........................................................................................................ 170<br />

List Box Component Attributes ....................................................................................................... 189<br />

Combo Box Component Attributes ................................................................................................. 193<br />

Display Sequence .................................................................................................... 201<br />

Controls Based on Property Types ............................................................................ 244<br />

Data Model Class Parameters ......................................................................................................... 253<br />

Data Model Property Parameters .................................................................................................... 253<br />

Object Data Model Callback Methods ............................................................................................ 255<br />

Custom Data Model Class Methods ................................................................................................ 260<br />

Menu Cell Attributes ....................................................................................................................... 268<br />

Tab Group Attributes ....................................................................................................................... 275<br />

Options for Extending <strong>Zen</strong> .............................................................................................................. 328<br />

Extending <strong>Zen</strong> with Composite Components ................................................................................. 328<br />

Extending <strong>Zen</strong> with Custom Components ...................................................................................... 332<br />

Custom Component Base Classes ................................................................................................... 333<br />

Datatype Classes ............................................................................................................................. 340<br />

Component Class Method Conventions .......................................................................................... 343<br />

Extending <strong>Zen</strong> with Custom Meters ............................................................................................... 353<br />

Application Class Elements ............................................................................................................ 362<br />

Page Class Parameters ..................................................................................................................... 364<br />

Special Variables on the Server Side ............................................................................................... 365<br />

Client-Side Functions and Variables ............................................................................................... 373<br />

Page Class Method Conventions ..................................................................................................... 375<br />

Page Class Server-side Callback Methods ...................................................................................... 377<br />

xiv<br />

<strong>Using</strong> <strong>Zen</strong>


Page Class Server Methods ............................................................................................................. 378<br />

Page Class Client-side Callback Methods ....................................................................................... 380<br />

Page Class Client-side Methods ...................................................................................................... 380<br />

Page Class Client-side Component Methods .................................................................................. 381<br />

Report Class Parameters .................................................................................................................. 411<br />

Report Display Attributes ................................................................................................................ 428<br />

<strong>Using</strong> <strong>Zen</strong><br />

xv


Preface<br />

This book is intended for Web application developers. It describes how to use <strong>Zen</strong>, the <strong>InterSystems</strong><br />

framework for Web application development.<br />

General Information<br />

The first several chapters in the book provide the general information required to become productive<br />

with <strong>Zen</strong>. Readers who are new to <strong>Zen</strong> should read the following chapters in sequence:<br />

• Introducing <strong>Zen</strong><br />

• <strong>Zen</strong> Tutorial<br />

• <strong>Zen</strong> Client and Server<br />

• <strong>Zen</strong> Application Concepts<br />

Experienced <strong>Zen</strong> programmers can choose specific topics from among the remaining chapters.<br />

Introducing <strong>Zen</strong> Components<br />

<strong>Zen</strong> provides a large set of Web page components and a variety of mechanisms for laying them out<br />

on the page. The following chapters provide information that applies to all <strong>Zen</strong> components:<br />

• <strong>Zen</strong> Component Concepts<br />

• <strong>Zen</strong> Layout<br />

• <strong>Zen</strong> Style<br />

Essential <strong>Zen</strong> Components<br />

The following chapters provide details about the most essential built-in <strong>Zen</strong> components:<br />

• <strong>Zen</strong> Tables<br />

• <strong>Zen</strong> and SVG<br />

• <strong>Zen</strong> Charts<br />

• <strong>Zen</strong> Forms<br />

• <strong>Zen</strong> Controls<br />

Complex <strong>Zen</strong> Components<br />

The following chapters describe the more complex <strong>Zen</strong> components, and explain how to extend the<br />

<strong>Zen</strong> component library with custom code.<br />

<strong>Using</strong> <strong>Zen</strong> 1


Preface<br />

• Model View Controller<br />

• Navigation Components<br />

• Popup Windows and Dialogs<br />

• Other <strong>Zen</strong> Components<br />

• Custom Components<br />

Developing <strong>Zen</strong> Applications<br />

The following chapters describe additional programming issues relating to <strong>Zen</strong>:<br />

• <strong>Zen</strong> Application Programming<br />

• <strong>Zen</strong> Security<br />

• <strong>Zen</strong> Localization<br />

• <strong>Zen</strong> Reports<br />

• <strong>Zen</strong> Wizards<br />

2 <strong>Using</strong> <strong>Zen</strong>


1<br />

Introducing <strong>Zen</strong><br />

Welcome to <strong>Zen</strong>!<br />

The <strong>Zen</strong> application framework provides a simple way to rapidly create complex, data-rich Web<br />

applications by assembling pre-built object components. These components automatically create<br />

standard HTML and JavaScript needed to render complex Web applications. Moreover, they provide<br />

a common object model that is shared between the user’s browser and the application logic running<br />

on the server.<br />

<strong>Zen</strong> is based on <strong>InterSystems</strong>’ successful Caché Server Page (CSP) and Caché Object Database technologies.<br />

These technologies offer a robust, scalable, and portable platform for hosting Web applications.<br />

<strong>Zen</strong> does not replace or deprecate Caché Server Pages in any way. Instead, <strong>Zen</strong> makes the development<br />

of web-based applications easier while building upon the basic features provided by CSP: performance,<br />

data access, security, localization, and configuration.<br />

1.1 The <strong>Zen</strong> Demo<br />

<strong>Zen</strong> includes a sample application, which you can try out as follows:<br />

1. Start your browser. You may use Firefox or Internet Explorer.<br />

2. Enter this URI:<br />

http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché.<br />

If you are unsure of the port number, start the System Management Portal. At the top of the page,<br />

click About. View the Web Server Port setting.<br />

<strong>Using</strong> <strong>Zen</strong> 3


Introducing <strong>Zen</strong><br />

1.2 Supported Browsers<br />

The browser you use with <strong>Zen</strong> must support SVG (Scalable Vector Graphics). <strong>Zen</strong> supports the following<br />

browsers:<br />

• Firefox 1.5 or later. This download is available from:<br />

http://www.mozilla.com/firefox/<br />

Support for SVG is built into Firefox.<br />

• Internet Explorer 6.0 or later.<br />

IE 6.0 does not support SVG natively, so you must download the free SVG Viewer from this<br />

Adobe site:<br />

http://www.adobe.com/svg/<br />

Note:<br />

<strong>InterSystems</strong> recommends that you use Firefox as your primary development browser, and<br />

reserve Internet Explorer for compatibility testing. Firefox offers better JavaScript and HTML<br />

troubleshooting options and can help track down programming problems. This is especially<br />

true if you use some of the many developer plug-ins available for Firefox.<br />

1.3 Benefits of <strong>Zen</strong><br />

The benefits of using <strong>Zen</strong> include:<br />

• Rapid Development—Assembling applications from pre-built components is a proven method for<br />

creating user interfaces rapidly. <strong>Zen</strong> makes it possible to use this approach for Web-based applications.<br />

• Simplicity—<strong>Zen</strong> uses a standard HTML client, so there are no additional client components<br />

required. There is no “middle” tier between server and client, so <strong>Zen</strong> applications are much easier<br />

to develop, deploy, and support.<br />

• Extensive Library of Components—The <strong>Zen</strong> library comes with a large set of pre-built components.<br />

These include all the standard control types as well as data-aware combo boxes, tables, grids, tabs,<br />

tree controls, menus, and grouping components.<br />

• Object Database Integration—<strong>Zen</strong> is tightly integrated with the underlying Caché object database.<br />

The <strong>Zen</strong> client and server communicate by sending objects back and forth. Underlying details<br />

such as encryption and data marshalling are handled automatically using proven Caché technology.<br />

4 <strong>Using</strong> <strong>Zen</strong>


Background Reading<br />

• Code Generation—Much of the code and business logic is generated automatically from higherlevel<br />

models, ensuring consistency and rapid development.<br />

• Extensibility—You can easily modify the look and feel of <strong>Zen</strong> applications by using standard CSS<br />

style sheets; by supplying different property values for the <strong>Zen</strong> components; or by creating your<br />

own custom components.<br />

• Integrated use of SVG—<strong>Zen</strong> lets you add interactive graphics to Web applications by means of a<br />

set of SVG (Scalable Vector Graphics) components. These components include pre-built charts<br />

and meters. In addition, you can create new graphical components.<br />

• Client Independence—<strong>Zen</strong> applications run in either Firefox or Internet Explorer. The <strong>Zen</strong> components<br />

insulate applications from the differences in behavior of these browsers.<br />

• Security—<strong>Zen</strong> offers tight integration with the security model provided by the Caché object<br />

database.<br />

• Form Handling—The <strong>Zen</strong> framework lets you define forms that contain a variety of controls for<br />

displaying and editing of data. The framework includes extensible support for loading data into<br />

forms; validating the contents of forms; and saving form contents.<br />

• Page Layout—<strong>Zen</strong> includes an extensible framework for specifying the grouping and layout of<br />

components on a Web page.<br />

• Event Management—<strong>Zen</strong> applications can easily define how their components respond to user<br />

events. All events are handled by invoking methods that can be defined to run within the client<br />

browser or on the data server.<br />

• Multilingual Support—For applications that must support multiple languages, <strong>Zen</strong> includes a<br />

mechanism that tracks which titles and captions need to be localized, and automatically builds a<br />

database of these values. This database can be exported as XML and given to a translator for<br />

conversion into other languages. At runtime, <strong>Zen</strong> automatically displays pages in the user’s preferred<br />

language.<br />

• Document Output—<strong>Zen</strong> includes an extensible framework for specifying the data contents and<br />

display layout of reports in XHTML or PDF format.<br />

1.4 Background Reading<br />

Before using <strong>Zen</strong>, you need a good understanding of the following topics:<br />

• HTML, JavaScript, and Cascading Style Sheets (CSS).<br />

Many excellent books are available through the Internet and commercial bookstores.<br />

• Caché, Caché Objects, Caché Server Pages, and Caché SQL.<br />

<strong>Using</strong> <strong>Zen</strong> 5


Introducing <strong>Zen</strong><br />

Depending on your level of experience, you might want to review the following books from the<br />

<strong>InterSystems</strong> online documentation category Caché Development Guides:<br />

- <strong>Using</strong> Caché Objects<br />

- <strong>Using</strong> Caché ObjectScript<br />

- <strong>Using</strong> Caché Server Pages (CSP)<br />

- <strong>Using</strong> Caché SQL<br />

6 <strong>Using</strong> <strong>Zen</strong>


2<br />

<strong>Zen</strong> Tutorial<br />

This chapter describes how to create some simple Web pages using <strong>Zen</strong>. The chapter is organized as<br />

a step-by-step tutorial. Topics include:<br />

• Hello World<br />

• Creating a <strong>Zen</strong> Application<br />

• Creating a <strong>Zen</strong> Page<br />

• Creating a <strong>Zen</strong> Report<br />

• <strong>Zen</strong> Naming Conventions<br />

• <strong>Zen</strong> Sample Applications<br />

2.1 Hello World<br />

The following steps display “Hello world!” on a <strong>Zen</strong> page:<br />

1. Start Caché Studio.<br />

2. Choose File > Change Namespace or F4.<br />

3. Choose the SAMPLES namespace.<br />

4.<br />

Choose File > New or Ctrl-N or the<br />

5. Click the Custom tab.<br />

6. Click the New <strong>Zen</strong> Page icon.<br />

icon.<br />

7. Click OK.<br />

<strong>Using</strong> <strong>Zen</strong> 7


<strong>Zen</strong> Tutorial<br />

8. For Package Name choose ZENDemo.<br />

9. In the Class Name field, type:<br />

hello<br />

10. For Application Name choose ZENDemo.Application.<br />

11. Click Next.<br />

12. Click Finish.<br />

13. Position the cursor at the start of this line:<br />

<br />

14. Press Enter.<br />

15. Move the cursor up to the blank line.<br />

16. Type a left angle bracket:<br />

<<br />

A context-sensitive list of XML elements displays.<br />

17. Click button.<br />

18. Press Enter.<br />

19. Type a space. A context-sensitive list of XML attributes displays.<br />

20. Click caption.<br />

21. Press Enter.<br />

22. Type:<br />

23.<br />

24.<br />

Hello world!"/><br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the<br />

icon.<br />

icon.<br />

Your simple new <strong>Zen</strong> page displays “Hello world!” on the face of a button.<br />

25. Also try steps 13–24 with:<br />

<br />

<br />

<br />

If you encounter difficulties during this exercise, return to The <strong>Zen</strong> Demo and Supported Browsers in<br />

the previous chapter. These topics provide useful background information for getting started with <strong>Zen</strong>.<br />

8 <strong>Using</strong> <strong>Zen</strong>


Creating a <strong>Zen</strong> Application<br />

2.2 Creating a <strong>Zen</strong> Application<br />

A <strong>Zen</strong> application class extends %ZEN.application to provide application-wide styling behavior. In this<br />

exercise you will create a <strong>Zen</strong> new application class, as follows:<br />

1. Start Caché Studio.<br />

2. Choose File > Change Namespace or F4.<br />

3. Choose the SAMPLES namespace.<br />

4.<br />

Choose File > New or Ctrl-N or the<br />

5. Select the Custom tab.<br />

6. Click the New <strong>Zen</strong> Application icon.<br />

icon.<br />

7. Click OK.<br />

The <strong>Zen</strong> Application Wizard presents the fields shown in the following table. For this exercise,<br />

enter the values shown in the right-hand column of the table.<br />

Field<br />

Package Name<br />

Class Name<br />

Application Name<br />

Description<br />

Meaning<br />

The package that will contain<br />

the new application class.<br />

The class name of the new<br />

application class.<br />

The logical name of the<br />

application.<br />

Any text that you want to use<br />

to describe the application.<br />

Value to Enter<br />

MyApp<br />

MyNewApp<br />

My New <strong>Zen</strong> Application<br />

This is my first new <strong>Zen</strong><br />

application.<br />

Click Finish.<br />

8. The <strong>Zen</strong> Application Wizard creates and displays a skeletal application class. It includes some<br />

pre-defined class parameters and an XData Style block as follows:<br />

<strong>Using</strong> <strong>Zen</strong> 9


<strong>Zen</strong> Tutorial<br />

/// This is my first new <strong>Zen</strong> application.<br />

Class MyApp.MyNewApp Extends %ZEN.application<br />

{<br />

/// This is the name of this application.<br />

Parameter APPLICATIONNAME = "My New <strong>Zen</strong> Application";<br />

/// This is the URL of the main starting page of this application.<br />

Parameter HOMEPAGE = "";<br />

/// This Style block contains application-wide CSS style definitions.<br />

XData Style<br />

{<br />

<br />

}<br />

}<br />

<br />

9.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

icon.<br />

2.3 Creating a <strong>Zen</strong> Page<br />

A <strong>Zen</strong> page class extends %ZEN.Component.page to define the contents and behavior of a Web page.<br />

In this exercise you will create a new <strong>Zen</strong> page class in several steps.<br />

2.3.1 Step 1: New Page Wizard<br />

Create the new class as follows:<br />

1. Start Caché Studio.<br />

2. Choose File > Change Namespace or F4.<br />

3. Choose the SAMPLES namespace.<br />

4.<br />

Choose File > New or Ctrl-N or the<br />

5. Select the Custom tab.<br />

6. Click the New <strong>Zen</strong> Page icon.<br />

icon.<br />

7. Click OK.<br />

The <strong>Zen</strong> Page Wizard presents the fields shown in the following table. For this exercise, enter the<br />

values shown in the right-hand column of the table.<br />

10 <strong>Using</strong> <strong>Zen</strong>


Creating a <strong>Zen</strong> Page<br />

Field<br />

Package Name<br />

Class Name<br />

Application<br />

Page Name<br />

Domain<br />

Description<br />

Page type<br />

Meaning<br />

The package that will<br />

contain the page class.<br />

The page class name.<br />

The package and class<br />

name of the application<br />

that this page belongs to.<br />

The logical name of this<br />

page within its application.<br />

The domain this page will<br />

use for localization of<br />

caption text.<br />

Any text that you want to<br />

use to describe the page.<br />

Regular page, or subclass<br />

of a template page class.<br />

Value to Enter<br />

MyApp<br />

MyNewPage<br />

MyApp.MyNewApp<br />

My Home Page<br />

For this exercise, leave the Domain field<br />

empty.<br />

My very first <strong>Zen</strong> page class.<br />

For this exercise, leave the Page type<br />

field with its default selection of Page.<br />

Click Next.<br />

8. The wizard prompts you to select an initial page layout, for example:<br />

• Column 2 — two columns, plus space for a title along the top<br />

• Title Page — space for a title along the top<br />

• Default — no pre-defined layout<br />

For this exercise, click Title Page. Then click Finish.<br />

9. The New Page Wizard creates and displays a skeletal <strong>Zen</strong> page with pre-defined class parameters<br />

and the XML blocks XData Style and XData Contents, as follows:<br />

<strong>Using</strong> <strong>Zen</strong> 11


<strong>Zen</strong> Tutorial<br />

/// My very first <strong>Zen</strong> page class.<br />

Class MyApp.MyNewPage Extends %ZEN.Component.page<br />

{<br />

/// Class name of application this page belongs to.<br />

Parameter APPLICATION = "MyApp.MyNewApp";<br />

/// Displayed name of this page.<br />

Parameter PAGENAME = "My Home Page";<br />

/// Domain used for localization.<br />

Parameter DOMAIN = "";<br />

/// This Style block contains page-specific CSS style definitions.<br />

XData Style<br />

{<br />

<br />

/* style for title bar */<br />

#title {<br />

background: #C5D6D6;<br />

color: black;<br />

font-family: Verdana;<br />

font-size: 1.5em;<br />

font-weight: bold;<br />

padding: 5px;<br />

border-bottom: 1px solid black;<br />

text-align: center;<br />

}<br />

<br />

}<br />

/// This XML block defines the contents of this page.<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

}<br />

}<br />

Title<br />

<br />

<br />

<br />

<br />

The XML blocks in this page class work together as follows:<br />

• XData Style defines a style rule called #title that defines a background color, padding,<br />

borders, and font characteristics for HTML output.<br />

• XData Contents provides an XMLNamespace keyword. The value<br />

http://www.intersystems.com/zen enables the Studio Assist type-ahead feature for<br />

built-in <strong>Zen</strong> components. You first experienced this feature during the Hello World exercise.<br />

• XData Contents uses the element to define a page object.<br />

• XData Contents uses the element to define a simple HTML excerpt for display in the<br />

browser. The id value title creates the connection between the html object and the #title<br />

rule from XData Style. The html object formats a string of text, Title. The resulting output<br />

functions as a simple title bar for the page.<br />

• XData Contents provides an empty . Later exercises add components here.<br />

12 <strong>Using</strong> <strong>Zen</strong>


Creating a <strong>Zen</strong> Page<br />

10.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

11.<br />

Choose View > Web Page or the icon.<br />

Your new <strong>Zen</strong> page displays as follows:<br />

icon.<br />

If you encounter difficulties when displaying any <strong>Zen</strong> page from Studio, you can display the page by<br />

opening a browser session and entering a URI in this format:<br />

http://localhost:57772/csp/samples/MyApp.MyNewPage.cls<br />

Where:<br />

• 57772 is the Web server port number assigned to Caché<br />

• samples is the namespace that contains the <strong>Zen</strong> page class (all-lowercase)<br />

• MyApp.MyNewPage is the <strong>Zen</strong> page package and class name (case-sensitive)<br />

2.3.2 Step 2: XData Contents Block<br />

In this exercise you will modify the element to add a simple button to the page. You can do<br />

this by typing text into the XData Contents block, or by using templates to generate a element<br />

with the correct syntax. This exercise uses both techniques:<br />

1. In Studio, open the page class.<br />

2. Select the text Title within the element. Replace Title with a meaningful string, for<br />

example:<br />

<strong>Zen</strong> Exercise Results<br />

3. Remove this line just after the element:<br />

<br />

Place the cursor between and .<br />

4. Choose Tools > Templates > Templates or press Ctrl-T to display the Studio Templates dialog.<br />

Choose <strong>Zen</strong> Element Wizard. Click OK.<br />

5. In the drop-down list of XML elements, choose button. Click Next. Add properties as follows:<br />

• In the caption row, click Edit. Enter a string value and click OK. For example:<br />

<strong>Using</strong> <strong>Zen</strong> 13


<strong>Zen</strong> Tutorial<br />

Press Me<br />

• In the id row, click Edit. Enter a string value and click OK. For example:<br />

myButton<br />

• In the onclick row, click Edit. Type a short JavaScript expression. For this exercise, use the<br />

following expression:<br />

zenPage.btnClick();<br />

Click OK.<br />

6. Click Finish. The XData Contents block now looks like this:<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<strong>Zen</strong> Exercise Results<br />

<br />

<br />

<br />

<br />

}<br />

New additions to this XData Contents block accomplish the following:<br />

• Define a button object as a child of the vgroup object. This places the button at the top lefthand<br />

corner of the display, under the title. The button is an instance of the<br />

%ZEN.Component.button class.<br />

• The id value myButton provides a way to find the button object programmatically.<br />

• The caption value Press Me indicates the text that will be displayed on the button when the<br />

page appears.<br />

• The onclick value zenPage.btnClick(); is a JavaScript expression that will be executed<br />

on the client when a user clicks this button.<br />

• At present, when you click this button it does nothing. The next exercise changes this.<br />

7.<br />

8.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the icon.<br />

Your new <strong>Zen</strong> page displays as follows:<br />

icon.<br />

14 <strong>Using</strong> <strong>Zen</strong>


Creating a <strong>Zen</strong> Page<br />

2.3.3 Step 3: Client-Side Method<br />

In the previous step you added this JavaScript expression to your definition:<br />

zenPage.btnClick();<br />

This expression executes a method called btnClick in an object called zenPage. zenPage is the<br />

JavaScript variable that represents the page object on the client side. btnClick is available to the<br />

JavaScript page object only if you define it in your <strong>Zen</strong> page class as a client-side method.<br />

In this exercise, you will add a JavaScript client-side method to your <strong>Zen</strong> page class, as follows:<br />

1. In Studio, open the page class.<br />

2. Position the cursor just below the closing curly brace of the XData Contents block.<br />

3. Choose Tools > Templates > Templates or press Ctrl-T to display the Studio Template dialog.<br />

Choose <strong>Zen</strong> Method Wizard. Click OK. The following dialog displays:<br />

Edit the dialog as follows:<br />

• Enter the name btnClick<br />

• Choose is an instance method<br />

• Choose runs on the client<br />

• Enter a description.<br />

• Uncheck the Try/Catch checkbox.<br />

• Click Finish. Your new method appears in the page class as follows:<br />

<strong>Using</strong> <strong>Zen</strong> 15


<strong>Zen</strong> Tutorial<br />

///What to do if the user clicks this button.<br />

Method btnClick() [Language = JavaScript]<br />

{<br />

// TODO: implement<br />

alert('Client Method');<br />

}<br />

4. Change the code within curly braces so the method now looks like this:<br />

5.<br />

6.<br />

///What to do if the user clicks this button.<br />

Method btnClick() [Language = JavaScript]<br />

{<br />

alert('Hello, World!');<br />

}<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the<br />

icon.<br />

icon.<br />

7. Click the “Press Me” button. Your JavaScript alert message displays:<br />

8. Click OK to close the popup.<br />

Some important things to notice about the btnClick method:<br />

• It is defined as an instance method (it does not use the ClassMethod keyword).<br />

• Its Language keyword is set to JavaScript. This means that the implementation of this method<br />

uses JavaScript. Studio syntax-colors and validates this method as JavaScript.<br />

• When this class is compiled, the btnClick method will not be available as a callable method on<br />

the server. It will, however, be made available as an instance method of the zenPage object on<br />

the client.<br />

• The class compiler resolves inheritance. This means that you can define JavaScript methods within<br />

a super class and they will automatically be available to any subclasses. While this is possible to<br />

accomplish in traditional JavaScript, it is also very tedious and error-prone. A lot of the power of<br />

<strong>Zen</strong> comes from this ability to support inheritance on both the server and client.<br />

• The body of this method uses the standard JavaScript alert method to display a message on the<br />

client.<br />

• At runtime, this method is run within the client (browser) environment.<br />

• The method is defined within the same logical unit (that is, the class) as the page definition that<br />

references it. This makes pages easy to develop and maintain.<br />

16 <strong>Using</strong> <strong>Zen</strong>


Creating a <strong>Zen</strong> Page<br />

2.3.4 Step 4: Viewing the HTML Output<br />

While viewing your <strong>Zen</strong> page in the browser, use the View Source option to look at the HTML served<br />

by the <strong>Zen</strong> page. You will see that the <strong>Zen</strong> page consists of the following elements, from top to bottom:<br />

• A standard HTML header<br />

• A set of included elements such as pre-generated JavaScript (for library components) and CSS<br />

(stylesheet) files.<br />

• Some generated JavaScript utility code (for error detection, timeout management, encrypted server<br />

calls, etc.)<br />

• JavaScript class definitions for any user-defined classes used on this page (such as the page object<br />

itself).<br />

• JavaScript code to create any client-side objects defined by the page. This is a client-side version<br />

of the same objects defined in the page’s XData Contents block.<br />

• HTML needed to display any components that generate HTML (such as the button component).<br />

• If needed, additional JavaScript code to “finalize” the client-side object model.<br />

2.3.5 Step 5: Server-Side Method<br />

In this exercise, you will make a simple modification in your new <strong>Zen</strong> page. This modification<br />

demonstrates the ability to invoke server logic from within a client page, as follows:<br />

1. In Studio, open the page class.<br />

2. <strong>Using</strong> techniques from the previous exercises, add a new button inside the XData Contents block.<br />

Give the new button the attribute values listed in the following table.<br />

Attribute<br />

id<br />

caption<br />

onclick<br />

Value to Enter<br />

myButtonToo<br />

No, Me!<br />

zenPage.BtnClickMe();<br />

Your XData Contents block should now resemble this one:<br />

<strong>Using</strong> <strong>Zen</strong> 17


<strong>Zen</strong> Tutorial<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<strong>Zen</strong> Exercise Results<br />

<br />

<br />

<br />

<br />

<br />

}<br />

3. Position the cursor just below the closing curly brace of the XData Contents block.<br />

4. Choose Tools > Templates > Templates or press Ctrl-T to display the Studio Template dialog.<br />

Choose <strong>Zen</strong> Method Wizard. Click OK. The following dialog displays:<br />

Edit the dialog as follows:<br />

• Enter the name BtnClickMe<br />

• Choose is an instance method<br />

• Choose runs on the server<br />

• Enter a description.<br />

• Uncheck the Try/Catch checkbox.<br />

• Click Finish. Your new method appears in the page class as follows:<br />

///When the user clicks the button, ask<br />

///the server which version it is running.<br />

Method BtnClickMe() [<strong>Zen</strong>Method]<br />

{<br />

// TODO: implement<br />

&js<br />

Quit<br />

}<br />

18 <strong>Using</strong> <strong>Zen</strong>


Creating a <strong>Zen</strong> Page<br />

5. Change the code within curly braces so the method now looks like this:<br />

///When the user clicks the button, ask<br />

///the server which version it is running<br />

Method BtnClickMe() [<strong>Zen</strong>Method]<br />

{<br />

Set msg = $ZVERSION<br />

&js<br />

Quit<br />

}<br />

6.<br />

7.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the icon.<br />

Your new <strong>Zen</strong> page displays as follows:<br />

icon.<br />

8. Click the “No, Me!” button. The following popup message appears. It displays the text returned<br />

by the ObjectScript $ZVERSION utility. This text is a full description of the Caché version that<br />

you are running:<br />

9. Click OK to close the popup.<br />

10. Use the View Source option of your browser to look at the HTML.<br />

Some important things to notice about the BtnClickMe method:<br />

• It is defined as an instance method.<br />

• It omits the Language keyword. This means that this method will use the default server scripting<br />

language (ObjectScript or Caché Basic, in this case ObjectScript).<br />

• It executes on the server but (as further notes explain) it also sends a hyperevent to the client.<br />

• It uses the <strong>Zen</strong>Method keyword. The <strong>Zen</strong>Method keyword means that this is a server-side method<br />

that can be called from the client. Even when this method is called from within the client (browser)<br />

environment, it is still executed on the server.<br />

<strong>Using</strong> <strong>Zen</strong> 19


<strong>Zen</strong> Tutorial<br />

• The method assigns the value of the $ZVERSION utility to the variable msg, then sends msg to<br />

the client so that the user can see the value in a JavaScript alert popup. The statement:<br />

&js< alert('#(msg)#'); ><br />

is an example of embedded JavaScript syntax. While executing your BtnClickMe method on<br />

the server, <strong>Zen</strong> finds the snippet of JavaScript code between &js< and > and sends this snippet<br />

to the client for execution.<br />

Note:<br />

This behavior is provided by the CSP hyperevent mechanism. For details see the book<br />

<strong>Using</strong> Caché Server Pages (CSP).<br />

• Within the embedded JavaScript, the syntax:<br />

#(msg)#<br />

is the convention for transferring the value of the variable msg from ObjectScript code executing<br />

on the server to embedded JavaScript executing on the client. For details, see <strong>Zen</strong> Runtime<br />

Expressions.<br />

• The client-side zenPage object can invoke your server-side BtnClickMe method.<br />

Because you defined BtnClickMe as an instance method, the server needs the current client-side<br />

object’s complete state to be able to execute the method.<br />

When zenPage invokes your server-side method, the client-side implementation of BtnClickMe<br />

gathers up any argument and object context information available on the client side, serializes the<br />

entire page object and sends it through to the server, then invokes the server-side method, all using<br />

the CSP session-encrypted hyperevent mechanism.<br />

• BtnClickMe does not return a value. This is intentional. When you use CSP hyperevents, a method<br />

with no return value automatically runs asynchronously (does not wait for a response). This way,<br />

the user interface does not appear to “freeze” as it would if it had to wait for a method to return a<br />

value.<br />

2.4 Creating a <strong>Zen</strong> Report<br />

A <strong>Zen</strong> report page extends %ZEN.Report.reportPage to display a database report. <strong>Zen</strong> reports support<br />

a variety of useful output formats including XHTML and PDF. In this exercise you will copy and<br />

modify an existing <strong>Zen</strong> report class and view it as XHTML.<br />

If you have a new Caché installation, you must first generate data records for the SAMPLES namespace.<br />

You only need to do this once per Caché installation. Enter the following URI in the browser:<br />

http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />

20 <strong>Using</strong> <strong>Zen</strong>


Where 57772 is the Web server port number that you have assigned to Caché.<br />

Now begin the report exercise as follows:<br />

1. Start Caché Studio.<br />

2. Choose File > Change Namespace or F4.<br />

3. Choose the SAMPLES namespace.<br />

4. Choose Tools > Copy Class.<br />

Creating a <strong>Zen</strong> Report<br />

5. The Class Copy dialog presents the fields shown in the following table. For this exercise, enter<br />

the values shown in the right-hand column of the table.<br />

Field<br />

Copy Class<br />

To<br />

Meaning<br />

The class to copy.<br />

The new class to create.<br />

Value to Enter<br />

ZENApp.MyReport<br />

MyApp.MyNewReport<br />

Check the Replace Instances of Class Name box.<br />

Click OK.<br />

6. The new class definition for MyApp.MyNewReport displays in Studio.<br />

7.<br />

8.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the<br />

icon.<br />

9. The report displays a report title and header block, followed by a table of information for each<br />

sales person in the database:<br />

icon.<br />

<strong>Using</strong> <strong>Zen</strong> 21


<strong>Zen</strong> Tutorial<br />

2.5 <strong>Zen</strong> Naming Conventions<br />

<strong>Zen</strong> programs are case-sensitive. If you are not experienced with case-sensitive programming, case<br />

might be your biggest adjustment in using <strong>Zen</strong>. Remember that a is not the same as A.<br />

The following naming conventions apply throughout the <strong>Zen</strong> code. These conventions use case to<br />

distinguish between different categories of method or property. myMethodName and MyMethodName<br />

are not the same name.<br />

Naming Conventions<br />

Convention<br />

Client-side methods are defined using the Language=JavaScript<br />

key phrase, and are written in JavaScript. They can be called from<br />

the client and, when called, run on the client. These names start<br />

with a lowercase letter and use an initial capital letter for each<br />

successive word (in-word capitalization). The same is true of<br />

client-only properties.<br />

<strong>Zen</strong> methods are defined using the keyword <strong>Zen</strong>Method. They<br />

can be called from the client, but are executed on the server.These<br />

methods are written in ObjectScript or Basic, but they may include<br />

embedded JavaScript that calls back to the client. Their names<br />

start with an uppercase letter and use in-word capitalization.<br />

Server-side methods use no special keyword. They are written<br />

in ObjectScript or Basic. They are available to be called from code<br />

that is executing on the server and, when called, they run on the<br />

server.These method names start with the % character. Server-only<br />

properties use this naming convention too.<br />

Typically, <strong>Zen</strong> class names start with lowercase and use in-word<br />

capitalization, similar to the conventions for client-side methods<br />

and properties. The exceptions to this rule include some of the<br />

server-only utility classes, which begin with an uppercase letter.<br />

Attribute and property names start with lowercase and use in-word<br />

capitalization, except for event handlers and callbacks.<br />

Attributes that identify event handlers for components follow the<br />

JavaScript convention of all-lowercase.<br />

Attributes that identify server-side callbacks for components start<br />

with On (capital letter O) and use in-word capitalization.<br />

Example<br />

myMethodName<br />

MyMethodName<br />

%MyMethodName<br />

tablePane<br />

filterOp<br />

onmousedown<br />

OnCreateDataSet<br />

22 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> offers many built-in variables, as described in <strong>Zen</strong> Application Programming. The most important<br />

of these are the two variables that represent the <strong>Zen</strong> page object on the client and server sides. These<br />

two variables conform to <strong>Zen</strong> naming conventions for client and server identifiers, as follows:<br />

• In JavaScript code that runs on the client side, the page object is zenPage<br />

• In ObjectScript or Basic code that runs on the server side, the page object is %page<br />

<strong>Zen</strong> Sample Applications<br />

2.6 <strong>Zen</strong> Sample Applications<br />

If you are an experienced Caché user, you are already familiar with the SAMPLES namespace. In<br />

particular, the sample application Cinema is a favorite with users learning about Caché Server Pages<br />

(CSP). <strong>Zen</strong> offers a large number of sample pages, organized into four packages in the SAMPLES<br />

namespace.<br />

If you have a new Caché installation, you must first generate data records for the SAMPLES namespace.<br />

You only need to do this once per Caché installation. Enter the following URI in the browser:<br />

http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché.<br />

Now you can view the <strong>Zen</strong> sample code at any time by following these steps:<br />

1. Start Caché Studio.<br />

2. Choose File > Change Namespace or F4.<br />

3. Choose the SAMPLES namespace.<br />

4. In the Workspace window, choose the Namespace tab and open the Classes category.<br />

Packages ZENApp, ZENDemo, ZENMVC, and ZENTest are available for you to explore.<br />

<strong>Using</strong> <strong>Zen</strong> 23


<strong>Zen</strong> Tutorial<br />

How to Access the Sample <strong>Zen</strong> Code in Studio<br />

2.7 <strong>Zen</strong> Wizards<br />

<strong>Zen</strong> supplies a rich set of application programming wizards that you can run from within Caché Studio.<br />

The exercises in this chapter use several of them. For a complete list and description of the available<br />

options, see the chapter <strong>Zen</strong> Wizards at the end of this book.<br />

24 <strong>Using</strong> <strong>Zen</strong>


3<br />

<strong>Zen</strong> Client and Server<br />

<strong>Zen</strong> is a client/server Web technology. The terms client and server are commonly used. This chapter<br />

explains how <strong>Zen</strong> uses these terms. The topics in this chapter are:<br />

• <strong>Zen</strong> and Caché Server Pages — A <strong>Zen</strong> application uses CSP technologies to serve Web pages to<br />

the client browser. This topic summarizes the CSP client/server relationship.<br />

• <strong>Zen</strong> Pages at Runtime — This topic extends the <strong>Zen</strong> and CSP discussion to explain how <strong>Zen</strong><br />

responds to HTTP requests. <strong>Zen</strong> responses to XML or SVG follow a similar sequence.<br />

3.1 <strong>Zen</strong> and Caché Server Pages<br />

Important:<br />

This topic briefly outlines material that fills several chapters in <strong>Using</strong> Caché Server<br />

Pages (CSP). If you are new to CSP, please study the detailed explanations in the<br />

other book.<br />

<strong>Using</strong> Caché Server Pages (CSP) describes the relationship between the client and server in CSP<br />

applications. It outlines the flow of events between issuing the HTTP request and displaying the page<br />

in the browser. <strong>Zen</strong> applications and <strong>Zen</strong> pages are CSP pages, so all of this information also applies<br />

to <strong>Zen</strong>.<br />

The following diagram summarizes the interactions between the CSP client and server.<br />

<strong>Using</strong> <strong>Zen</strong> 25


<strong>Zen</strong> Client and Server<br />

How Caché Server Pages Work<br />

Numbers in the previous diagram highlight the flow of events on the client and server while CSP<br />

processes an HTTP request. The sequence is as follows:<br />

1. The browser (or similar Web client) makes an HTTP request.<br />

2. If the Web server determines that this is a CSP request, it dispatches the request to the CSP<br />

Gateway installed on the Web Server.<br />

Alternatively, if the request is for a static file (such as an .html or .jpg file), the Web server finds<br />

the file within the local file system and sends its contents back to the client.<br />

3. The CSP Gateway repackages the request and sends it to the correct Caché server.<br />

26 <strong>Using</strong> <strong>Zen</strong>


4. The Caché server decodes the message, determines which event handling class (part of your<br />

application) should process the event, and invokes the OnPage method in that class.<br />

<strong>Zen</strong> pages are CSP pages, so each <strong>Zen</strong> page class has an OnPage method. However, <strong>Zen</strong> pages<br />

offer a much wider selection of potential actions than CSP pages, with a correspondingly rich set<br />

of methods that CSP pages do not provide.<br />

5. The Caché server returns the output of the OnPage method to the CSP Gateway as an HTTP<br />

response.<br />

6. The CSP Gateway hands the HTTP response to the Web server (actually, Caché streams the<br />

response back to the Web Server via the CSP Gateway).<br />

7. The Web server returns the response to the Web browser which then processes the response. In<br />

the case of HTML, it displays the page. There may be other results depending on what type of<br />

data the response contains.<br />

<strong>Zen</strong> applications use CSP technologies to:<br />

• Filter and respond to HTTP requests.<br />

• Manage sessions and session lifecycle.<br />

• Manage user identity, authentication, and access control.<br />

• Provide the hyperevent mechanism used to call server methods from the client.<br />

• Call from the server to execute code securely on the client.<br />

<strong>Zen</strong> Pages at Runtime<br />

Important:<br />

If you make use of the CSP session preserve mode, be aware that the server-side <strong>Zen</strong><br />

page (%page) and application (%application) objects are not preserved between<br />

server requests.<br />

3.2 <strong>Zen</strong> Pages at Runtime<br />

A <strong>Zen</strong> page automatically responds to HTTP requests from a browser and serves up a complete HTML<br />

document to satisfy such a request. <strong>Zen</strong> pages can also satisfy other types of requests, such as for XML<br />

or SVG content. The behavior for XML or SVG is documented in later chapters. It is similar to the<br />

HTML behavior documented in this chapter.<br />

The following sequence displays a <strong>Zen</strong> page in a browser window:<br />

1. The Web browser sends an HTTP request that names a specific <strong>Zen</strong> page. The Caché server<br />

receives the request and automatically routes it to the <strong>Zen</strong> page class.<br />

Note:<br />

CSP handles this step. Details appear in the previous topic.<br />

<strong>Using</strong> <strong>Zen</strong> 27


<strong>Zen</strong> Client and Server<br />

2. The page class invokes its %OnBeforeCreatePage callback method. This method provides the<br />

opportunity for the application to perform any setup work that may be required before<br />

%CreatePage begins execution.<br />

3. The page class creates an instance of itself on the Caché server.<br />

The page class invokes its class method %CreatePage. This method creates the set of component<br />

objects and adds these objects as children of the page object.<br />

When a <strong>Zen</strong> page class contains a description of the page in XML format (as described in later<br />

chapters) <strong>Zen</strong> automatically generates a %CreatePage method whenever the class is compiled.<br />

The compiler uses the information in XData Contents to generate the method.<br />

Alternatively, a programmer may omit the XData Contents block and implement %CreatePage<br />

manually. This more complex option gives the opportunity to create dynamic page content.<br />

4. The page class invokes its %OnAfterCreatePage callback method. In this method, the application<br />

can modify the content generated by %CreatePage in any way that is needed.<br />

After %OnAfterCreatePage completes execution, there is a page object in memory that contains<br />

some number of child component objects. This page object is a document object model (DOM)<br />

that will be used to draw the HTML needed to display the page.<br />

5. The page object constructs an HTML document from its DOM.<br />

The page invokes its %DrawHTML method. Every <strong>Zen</strong> page and component object has a<br />

%DrawHTML method that knows how to render the object as HTML. In the case of a <strong>Zen</strong> page,<br />

the %DrawHTML method supplies:<br />

• The page title.<br />

• Any meta-HTML tags needed by the page.<br />

• Any content needed to support hyperevents (the mechanism used to make in-page calls back<br />

to the server).<br />

• Include statements for any required JavaScript or CSS include files.<br />

• JavaScript needed to define the set of client component classes used on the page.<br />

• JavaScript needed to create and initialize the set of client component objects used on the page.<br />

That is, a client-side version of the server-side page object is created.<br />

• Default CSS style definitions defined by the component classes.<br />

• CSS style definitions defined by the application class.<br />

• CSS style definitions defined by the page class. (This order is important as it allows the<br />

application settings to override defaults and page settings to override application settings).<br />

• The HTML content of every component on the page (obtained by invoking the %DrawHTML<br />

method for every component on the page).<br />

28 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Pages at Runtime<br />

As with %CreatePage, for the most part a <strong>Zen</strong> programmer can ignore %DrawHTML. Caché<br />

generates and invokes it automatically. The important fact about %DrawHTML is when it occurs.<br />

%DrawHTML is the last step before the page leaves the server.<br />

The <strong>Zen</strong> programmer must ensure that all adjustments to the page are complete before the end of<br />

%OnAfterCreatePage. After that, Caché draws whatever is in the DOM.<br />

6. The Caché server delivers the HTML document to the client, and the browser displays the HTML<br />

document.<br />

Note:<br />

CSP handles this step. Details appear in the previous topic.<br />

The following diagram illustrates the sequence described above. This <strong>Zen</strong> diagram builds on the CSP<br />

diagram from the previous topic. It using regular numbers for CSP steps and highlights the <strong>Zen</strong> steps<br />

with larger, bold numbers such as:<br />

<strong>Using</strong> <strong>Zen</strong> 29


<strong>Zen</strong> Client and Server<br />

How <strong>Zen</strong> Pages Work<br />

30 <strong>Using</strong> <strong>Zen</strong>


4<br />

<strong>Zen</strong> Application Concepts<br />

A <strong>Zen</strong> application specifies the full set of activities that can result when a <strong>Zen</strong> client and server interact.<br />

These activities may consist of displaying Web pages, issuing queries to a database, writing data to<br />

disk, and more. When you create a <strong>Zen</strong> application, you create a suite of <strong>Zen</strong> classes that specify these<br />

activities. The language you use for these classes is Caché ObjectScript — with embedded snippets<br />

of XML, HTML, SVG, and JavaScript as needed.<br />

If you are new to Caché objects and the ObjectScript programming language, the discussion in this<br />

chapter will make most sense after you have mastered the supporting material available in other books.<br />

The best starting points are <strong>Using</strong> Caché Objects and <strong>Using</strong> Caché ObjectScript.<br />

The examples in this book use ObjectScript, but you can also use Caché Basic as your programming<br />

language. See <strong>Using</strong> Caché Basic.<br />

4.1 <strong>Zen</strong> Applications<br />

A <strong>Zen</strong> application consists of the following parts:<br />

An Application class<br />

Page classes<br />

Every <strong>Zen</strong> application has an application class. This is a class derived from %ZEN.application<br />

that provides application-wide behavior such as a common style sheet. The style sheet is<br />

specified as an XML block embedded within the class.<br />

An application consists of one or more pages. Each page is a class derived from<br />

%ZEN.Component.page which is, in turn, a subclass of both %CSP.Page and<br />

%ZEN.Component.component.<br />

<strong>Using</strong> <strong>Zen</strong> 31


<strong>Zen</strong> Application Concepts<br />

Component classes<br />

Every page contains components. Components provide “look and feel” and permit the user<br />

to interact with the page. All components are derived from %ZEN.Component.component.<br />

They include buttons, tables, list boxes, text fields, panels — essentially any item that can be<br />

displayed on a page.<br />

<strong>Zen</strong> Application with Pages and Components<br />

This architecture works as follows:<br />

• A <strong>Zen</strong> application consists of page classes.<br />

• Every <strong>Zen</strong> page identifies the application that it belongs to.<br />

• Every <strong>Zen</strong> page consists of a page object and a set of component objects.<br />

• The set of components for a page is defined using a block of XML embedded into the page class.<br />

• The page class can also define a set of methods that provide additional behavior, such as<br />

responding to user actions. These methods can run within the browser, or on the server, depending<br />

on how the code is written.<br />

• When the client sends a page request, the page object and all of its constituent component objects<br />

are instantiated on the Caché server. This is the object tree.<br />

• This object tree can be further modified by user code on the Caché server.<br />

32 <strong>Using</strong> <strong>Zen</strong>


• The object tree generates all the CSS (style sheet), JavaScript (client logic) and HTML (layout<br />

instructions) needed to display the page within the client browser. Alternatively, a page could<br />

generate XML or SVG.<br />

• On the client browser, the same object tree is automatically recreated as a set of JavaScript objects.<br />

• Properties and methods of the object tree are thus available to the client.<br />

• As the user interacts with a page, events are fired that invoke the various methods of the client<br />

object tree. Some of these methods execute within the browser, while others can be defined to run<br />

back on the server (for database access, etc.).<br />

• <strong>Zen</strong> automatically manages any calls that a page makes back to the server, including session<br />

context, security, and synchronizing changes between the client and the server.<br />

• Users create <strong>Zen</strong> applications by assembling classes (both pre-built and user-defined) into larger<br />

functional units: components are assembled into pages, and pages are assembled into applications.<br />

<strong>Zen</strong> Page Synchronized on Client and Server at Runtime<br />

<strong>Zen</strong> Pages<br />

4.2 <strong>Zen</strong> Pages<br />

A <strong>Zen</strong> page class consists of:<br />

• A contents definition—An XML block embedded within the page class. It defines the set of<br />

components that make up the page, along with their settings. It is possible to define the contents<br />

of a page programmatically, but in most cases an XML block is more convenient.<br />

<strong>Using</strong> <strong>Zen</strong> 33


<strong>Zen</strong> Application Concepts<br />

• Style overrides—An XML block embedded within the page class. It defines page-specific overrides<br />

of CSS styles for the components on this page.<br />

• Event-handling methods—A page class typically contains a number of methods that handle events<br />

associated with a page, such as when the user interacts with a component. Some of these methods<br />

may run on the server and some on the client. Later chapters provide details.<br />

Defining the Look and Feel of a <strong>Zen</strong> Page<br />

4.3 <strong>Zen</strong> Components<br />

<strong>Zen</strong> component classes define the behavior and layout of the page. Every <strong>Zen</strong> component has the following<br />

characteristics:<br />

• Defines a set of properties and methods that determine its runtime state and behavior.<br />

• Defines how its initial HTML is drawn (if any). It is also possible to define components that only<br />

render themselves using client-side, dynamic HTML.<br />

• Defines a standard CSS style sheet that specifies how it should appear on the page. Applications<br />

can selectively override these styles without having to modify the pre-built components.<br />

34 <strong>Using</strong> <strong>Zen</strong>


• Defines settings that adjust the appearance or behavior of a component. A <strong>Zen</strong> component class<br />

formally exposes certain settings so that it is easy to dynamically modify these setting values<br />

while designing a <strong>Zen</strong> page.<br />

• New component classes can be derived from existing classes. <strong>Zen</strong> automatically provides inheritance<br />

for the client JavaScript classes it creates.<br />

• New components are automatically ready for use within a page’s XML content definition.<br />

Component classes vary in complexity from simple wrappers for native HTML controls to full-featured<br />

calendar and grid controls. Components include the following specialized types:<br />

• Controls display data and allow for user input (such as text or button controls).<br />

• Groups contain sets of other components (such as groups, tab groups, menus, and forms).<br />

• Panes display rich information (such as a tables retrieved from queries).<br />

• Other components simply display data on the page.<br />

<strong>Zen</strong> Components<br />

<strong>Using</strong> <strong>Zen</strong> 35


5<br />

<strong>Zen</strong> Component Concepts<br />

Components provide layout, style, and behavior for the page. The following table defines these<br />

commonly used terms. These definitions are important because each <strong>Zen</strong> component provides a large<br />

number of attributes that you can manipulate as you program the application. Some of these attributes<br />

affect layout, some style, and some behavior. With a strong grounding in these concepts, you can<br />

manipulate attributes fluently to get the results you want from <strong>Zen</strong> components.<br />

<strong>Using</strong> <strong>Zen</strong> 37


<strong>Zen</strong> Component Concepts<br />

Term<br />

Page<br />

Illustration<br />

Component Concepts<br />

Summary<br />

The rectangular display in a browser window.<br />

Layout<br />

The position of each component, and of each<br />

group of components, on the page.<br />

Style<br />

The visual appearance of components,<br />

regardless of their position on the page.<br />

Behavior<br />

An application action that results from user<br />

input, a timer, or some other event.<br />

5.1 Page<br />

A page is initially empty. It fills with components as you add them. A layout strategy is necessary to<br />

determine where these components appear on the page.<br />

38 <strong>Using</strong> <strong>Zen</strong>


Layout<br />

5.2 Layout<br />

As <strong>Zen</strong> constructs a page for display, it adds components individually, one after another, according to<br />

the description that you have provided in the page class. The user is not aware of the page construction<br />

process. The user only sees that a page appears. However, as a <strong>Zen</strong> programmer, you must understand<br />

the construction process so that your pages lay themselves out exactly as you intend.<br />

Components are contained within groups: a special type of component that can contain zero or more<br />

components. A group is responsible for the placement of its components on the page. The page is itself<br />

a group. <strong>Zen</strong> generates standard HTML table elements based on the group definition. You can cause<br />

components to line up vertically or horizontally, by enclosing them within a vertical or horizontal<br />

group. Generally, the largest width or height of any component in a group determines the overall width<br />

or height of the group on the page. A spacer component is available to help insert additional space<br />

between components in the group. The entire group places itself on the page as one component.<br />

Certain components permit layers, similar to sheets of paper that occupy one position in a stack. Only<br />

one layer is revealed at one time, based on user clicks. Menus and tabs work on this principle.<br />

Other components may have variable size, depending on their state. For example, if an expando list<br />

is closed, it contains only one item and is short. If the list is opened, it may contain many items; then<br />

it is long. The opened list could push aside other components later in the layout, causing a shift in the<br />

physical geography of the page. Or, the containing group may have a fixed size larger than the maximum<br />

expected list size, allowing the list to expand and contract within the larger boundary without affecting<br />

the page layout.<br />

For details about the built-in <strong>Zen</strong> component expando, see Navigation Components.<br />

<strong>Zen</strong> manages layout by generating HTML and CSS style statements based on the inputs that you provide<br />

<strong>Zen</strong>. Essentially there are three ways to specify your layout intentions to <strong>Zen</strong>:<br />

• Let the containing group lay out its components.<br />

• Provide CSS style statements to <strong>Zen</strong>.<br />

• Use client-side JavaScript to dynamically change the geography of the page.<br />

For details, see the chapter <strong>Zen</strong> Layout.<br />

Scalable Vector Graphics (SVG) components are handled differently from other types of page content.<br />

For details see the chapter <strong>Zen</strong> and SVG.<br />

<strong>Using</strong> <strong>Zen</strong> 39


<strong>Zen</strong> Component Concepts<br />

5.3 Style<br />

Style determines the visual appearance of a component. <strong>Zen</strong> manages style by generating standard<br />

CSS statements based on the inputs that you provide <strong>Zen</strong>.<br />

There are many style attributes that you can set for each component. These include background color,<br />

size, fill patterns, line width, and font family, just to name a few. You can accept the default styles.<br />

You can also override styles at the component, page, or application level.<br />

For details, see the chapter <strong>Zen</strong> Style.<br />

5.4 Behavior<br />

Behavior refers to an internal or external application action that is triggered by user input, a timer, or<br />

some other type of event. Behavior encompasses a wide range of topics in this book, from processing<br />

user clicks and key presses to automatically generating tables based on database queries.<br />

Component behavior is unique per component. Subsequent chapters provide details as they discuss<br />

each type of <strong>Zen</strong> component. These chapters include:<br />

• <strong>Zen</strong> Tables<br />

• <strong>Zen</strong> and SVG<br />

• <strong>Zen</strong> Charts<br />

• <strong>Zen</strong> Forms<br />

• <strong>Zen</strong> Controls<br />

• Model View Controller<br />

• Navigation Components<br />

• Popup Windows and Dialogs<br />

• Other <strong>Zen</strong> Components<br />

• Custom Components<br />

40 <strong>Using</strong> <strong>Zen</strong>


Customization<br />

5.5 Customization<br />

<strong>Zen</strong> serves a wide audience range. At one end is the programmer who wants to use <strong>Zen</strong> to quickly<br />

assemble a user interface for a data-rich Web application. This programmer rapidly places <strong>Zen</strong> components<br />

on the page with the goal of allowing the user to see and manipulate the underlying data.<br />

At the other end of this range is the programmer who wants to use <strong>Zen</strong> for pinpoint control of the<br />

layout, style, and behavior of each component on the page. This programmer may react to introductory<br />

topics with this phrase: “But I want to...”<br />

Everyone can relax.<br />

<strong>Zen</strong> provides ample opportunities for customization. In addition to the wide range of variations available<br />

by manipulating layout, style, and behavior of built-in components, you can create new components,<br />

or even replace the <strong>Zen</strong> layout handler with custom code. For details, see the chapter Custom Components.<br />

On the other hand, customization is entirely optional. Everyone should begin by reading the next several<br />

chapters. Come to appreciate the power, ease, and flexibility of <strong>Zen</strong>. Then, after understanding what<br />

<strong>Zen</strong> provides, make your own decision about whether or not to extend it. The option is always there.<br />

<strong>Using</strong> <strong>Zen</strong> 41


6<br />

<strong>Zen</strong> Layout<br />

Previous chapters have introduced <strong>Zen</strong> components as classes. It is true that components are classes.<br />

All <strong>Zen</strong> components extend the class %ZEN.Component.component. However, when you place <strong>Zen</strong><br />

components on the page, your primary programming language is usually not ObjectScript. It is XML.<br />

This chapter explains how to lay out <strong>Zen</strong> pages using XML:<br />

• The chapter begins with an XData Contents example<br />

• The next several topics discuss the XML elements in the example:<br />

- — The top-level container element<br />

- — Allows you to place HTML directly on the page<br />

- — Creates a horizontal row of components<br />

- — Creates a vertical column of components<br />

- — Creates space between groups<br />

- — Subdivides the page into regions<br />

• The chapter ends by discussing:<br />

- How to organize XData Contents using template pages<br />

- The HTML page that <strong>Zen</strong> generates from XData Contents<br />

<strong>Using</strong> <strong>Zen</strong> 43


<strong>Zen</strong> Layout<br />

6.1 XData Contents<br />

When you prepare a <strong>Zen</strong> page class for an application, you place components on the page by providing<br />

an XData Contents block. XData Contents is a well-formed XML document that describes the layout<br />

and (optionally) style and behavior of the page.<br />

Each XML element in the document corresponds to a component class of the same name. The following<br />

sample XData Contents block includes the XML elements , , , ,<br />

, and . These XML elements represent the <strong>Zen</strong> classes %ZEN.Component.page,<br />

%ZEN.Component.html, %ZEN.Component.hgroup, and so on.<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

My Title<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

When you compile the class that contains the previous XData Contents block, <strong>Zen</strong> generates the code<br />

that displays this page in the browser. At runtime, this code instantiates the indicated component classes<br />

as children of the page object. <strong>Zen</strong> handles these details automatically and transparently, as described<br />

in the chapter <strong>Zen</strong> Application Concepts.<br />

As the programmer laying out an XData Contents block, you do not work with component classes<br />

directly. You work with the XML projection of the component classes. For each component, this<br />

projection consists of:<br />

• An XML element with the same name as the class (, , , etc.)<br />

• XML attributes, which are properties of that class (width, height, etc.)<br />

This convention gives you the power of the <strong>Zen</strong> runtime environment for serving <strong>Zen</strong> pages, without<br />

requiring you to understand the underlying mechanisms in detail. You use the XML projection to place<br />

components on the page, and <strong>Zen</strong> generates the HTML that displays these components in the browser.<br />

44 <strong>Using</strong> <strong>Zen</strong>


Pages<br />

6.2 Pages<br />

The XData Contents block contains one element that acts as the top-level container for all the<br />

XML elements in the block. A is a group component with the standard group attributes and<br />

the unique attributes listed in the following table.<br />

Attribute<br />

title<br />

xmlns<br />

Description<br />

Use this attribute to store page title text. This text is not automatically used<br />

on the page, but the attribute is available should you want to refer to this text<br />

programmatically. If you do not specify a value for title it takes its value from<br />

the page class parameter PAGETITLE.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

The title value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

Allows you to include an XML namespace declaration for the .<br />

As you add custom components, chances increase that there will be conflicts<br />

between components in different namespaces. Adding the xmlns attribute<br />

prevents this.<br />

6.3 Titles<br />

The first item most pages need is a title bar. The title bar answers the user’s implicit question: “Where<br />

am I” <strong>Zen</strong> offers several elements that can serve this purpose. They work in entirely different ways:<br />

• for simple titles<br />

• for complex titles<br />

• A custom component to use as your title bar<br />

<strong>Using</strong> <strong>Zen</strong> 45


<strong>Zen</strong> Layout<br />

6.3.1 Simple Titles<br />

draws a title box along with an optional subtitle. You can use to provide a<br />

simple title for any component, including the page itself. Simply make the first child<br />

component inside the component whose title you want it to be. For example:<br />

<br />

<br />

<br />

<br />

Components like have a caption attribute and so do not need to provide a label.<br />

is most useful and appropriate for a or . has the attributes listed<br />

in the following table.<br />

Attribute<br />

title<br />

subtitle<br />

titleStyle<br />

Description<br />

Title text.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

The title value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

(Optional) Subtitle text.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

The subtitle value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

(Optional) String containing a CSS style statement such as:<br />

"color:red; background: yellow;"<br />

There is also a element that omits the subtitle and titleStyle attributes.<br />

46 <strong>Using</strong> <strong>Zen</strong>


Titles<br />

6.3.2 Complex Titles<br />

The element permits you to insert an arbitrary HTML excerpt on the <strong>Zen</strong> page. You can use<br />

the component to output title text in the appropriate font and size. You can use to<br />

quickly produce a title when you are first drafting the page. Simply enclose the desired HTML tags<br />

inside and . For example:<br />

<br />

<br />

Welcome to My Application!<br />

You are Here:<br />

<br />

<br />

<br />

The real power of the element comes from its optional OnDrawContent attribute.<br />

OnDrawContent identifies a server-side callback method that provides HTML content by using &html<br />

or by using the WRITE command. If defined, this callback is invoked on the server when this component<br />

is drawn. The value of OnDrawContent must be the name of a server-only method in the page class<br />

that contains this component. This method must accept an optional %String as input and return a<br />

%Status data type. What is significant about this feature is that server-side methods normally consist<br />

of ObjectScript code, whereas a callback referenced by OnDrawContent may consist of ObjectScript<br />

code plus as much HTML as you wish to embed within &html or WRITE.<br />

Thus, a page class that contains an XData Contents block with this line:<br />

<br />

must also contain a server-side callback method called DrawMessage that meets the above criteria.<br />

The following example is from the ZENApp.HelpDesk class in the SAMPLES namespace:<br />

Method DrawMessage(pSeed As %String) As %Status<br />

{<br />

#; create a random message<br />

Set tColors = $LB("red","green","blue","black","orange")<br />

Set tColor = $LG(tColors,$R($LL(tColors))+1)<br />

Set tMsgs = $LB("Fresh coffee in kitchen!",<br />

"Company share price has gone up.",<br />

"The boss is coming!",<br />

"Customer crisis!",<br />

"Lunch Time!")<br />

Set tMsg = $LG(tMsgs,$R($LL(tMsgs))+1)<br />

&html<br />

}<br />

Quit $$$OK<br />

For more detail, see the Other <strong>Zen</strong> Components chapter, topic.<br />

<strong>Using</strong> <strong>Zen</strong> 47


<strong>Zen</strong> Layout<br />

6.4 Groups<br />

A group component extends %ZEN.Component.group. A group component is the only type of component<br />

that can contain child components. That is why components such as pages, panes, menus, forms, and<br />

composites all inherit from %ZEN.Component.group.<br />

6.4.1 Layout Strategy<br />

Each group is responsible for the layout of its children on the page. A group can have a horizontal or<br />

vertical layout. With the exception of and , every <strong>Zen</strong> group and page has vertical<br />

layout by default. You can reset to horizontal layout by providing the layout attribute for the group.<br />

layout may have the following values:<br />

• "horizontal" — Lay out components horizontally. When <strong>Zen</strong> generates the page, it constructs<br />

an HTML table row to contain the child components.<br />

• "vertical" — Lay out components vertically. When <strong>Zen</strong> generates the page, it constructs an<br />

HTML table column to contain the child components.<br />

• "" or omitted — Default to vertical layout.<br />

6.4.2 Simple Group Components<br />

The following table lists group components such as you have seen in previous code examples. These<br />

are all derived from %ZEN.Component.group.<br />

Component<br />

<br />

<br />

Description<br />

The basic group. Used to create a group of components, either for layout<br />

purposes or to treat a set of components as a logical unit (for example<br />

making them hidden or visible as a unit). The attributes of the group<br />

component control the layout of its child components.<br />

A horizontal group, identical to a component with its layout<br />

property set to "horizontal". For example:<br />

<br />

<br />

<br />

<br />

<br />

<br />

A specialized group component with layout set to "vertical" and cellVAlign<br />

set to "top".<br />

48 <strong>Using</strong> <strong>Zen</strong>


Groups<br />

Component<br />

<br />

<br />

<br />

Description<br />

A specialized group component with an additional attribute, paneName,<br />

that references an XData block outside XData Contents.<br />

The is not a group component, but it is useful within groups.<br />

Use with a width value to inject additional space in a horizontal<br />

group, or height for additional space within a vertical group.<br />

A vertical group, identical to a component with its layout property<br />

set to "vertical". For example:<br />

<br />

<br />

<br />

<br />

<br />

6.4.3 Menu Components<br />

Menu components are groups derived from the %ZEN.Component.group class. Being a group permits<br />

the menu to contain child components. A later chapter, Navigation Components, describes how to use<br />

menus.<br />

Component<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Description<br />

A specialized form of group that displays a set of menu choices.<br />

A with layout set to "horizontal".<br />

A specialized whose tabs present menus.<br />

An item within a <br />

A separator within a .<br />

Defines a group of components that are used as a tab within a<br />

or .<br />

A specialized group that contains components (which<br />

themselves contain components). One tab at a time is visible.When<br />

the user selects a new tab, its contents become visible and the<br />

other tabs are hidden.<br />

A with layout set to "vertical".<br />

<strong>Using</strong> <strong>Zen</strong> 49


<strong>Zen</strong> Layout<br />

6.4.4 Complex Group Components<br />

The <strong>Zen</strong> library contains a number of other classes derived from %ZEN.Component.group. The following<br />

table lists these group components. Later chapters describe them in full.<br />

Component<br />

<br />

<br />

<br />

<br />

<br />

Description<br />

A specialized form of the group component that lets the user show<br />

or hide the members of a group by clicking on a small icon: a plus<br />

sign to expand (show) the group, or a minus sign to contract (hide)<br />

the group.<br />

A group that wraps its members within an HTML <br />

element. The draws an outer box around the children<br />

and displays a title within this box. creates a visual panel<br />

that organizes a large form.<br />

A form is defined as a group, so that it can contain child<br />

components.<br />

Defines a set of components that act together as a modalGroup.<br />

This is a set of components that are initially not displayed but can<br />

later be displayed with modal behavior.<br />

A specialized group that defines the layout for a single entry, then<br />

lays out multiple entries of this type based on data supplied by a<br />

runtime query.<br />

6.4.5 Group Layout and Style Attributes<br />

The following table lists the XML attributes that apply to all group components. These attributes can<br />

affect the positioning or appearance of components in the groups.<br />

50 <strong>Using</strong> <strong>Zen</strong>


Groups<br />

Group Layout and Style Attributes<br />

Attribute<br />

<strong>Zen</strong><br />

component<br />

attributes<br />

cellAlign<br />

Description<br />

Groups have the same general-purpose attributes as any <strong>Zen</strong><br />

component. The next chapter, <strong>Zen</strong> Style, describes them.<br />

Specifies horizontal alignment for child components within the group<br />

table.The possible values are "left", "right", "center", and "even". cellAlign<br />

behavior depends on the layout strategy for the group:<br />

• Horizontal — A cellAlign value of "left" or "right" places the child<br />

components towards the left or right edges of the group, respectively.<br />

"center" places the child components in the horizontal center of the<br />

group with additional space added on either side of the children.<br />

"even" places the child components in the horizontal center of the<br />

group, with no additional space added.<br />

• Vertical — cellAlign specifies the default vertical alignment used by<br />

the elements containing the child components. "even" is the<br />

same as "center" in this case. An individual child component can<br />

override cellAlign by setting its own align value. For align, see<br />

Component Style Attributes.<br />

When specifying cellAlign, also set the height or width property of the<br />

group, to control how the group takes up the space provided by its container.<br />

For vertical alignment, set cellVAlign instead of cellAlign.<br />

cellSize<br />

How much space (in the direction specified by the layout strategy) to<br />

allot to the elements used to contain each child component within<br />

the layout table. Possible values are:<br />

• "same" — Attempt to allot the same amount of space to each component.<br />

• "stretch" — Allot space to each component based on its relative<br />

value of slice. For slice, see Component Style Attributes.<br />

cellStyle<br />

String containing a CSS style statement such as:<br />

"color:red; background: yellow;"<br />

<strong>Zen</strong> applies this style to the elements used to contain each child<br />

component within the layout table. An individual child component can<br />

override cellStyle by setting its own containerStyle value. For<br />

containerStyle, see Component Style Attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 51


<strong>Zen</strong> Layout<br />

Attribute<br />

cellVAlign<br />

Description<br />

Specifies vertical alignment for child components within the group table.<br />

The possible values are "top", "bottom", "middle", and "even". cellVAlign<br />

behavior depends on the layout strategy for the group:<br />

• Vertical — A cellVAlign value of "top" or "bottom" places the child<br />

components towards the top or bottom edges of the group, respectively.<br />

"middle" places the child components in the vertical center of<br />

the group with additional space added above and below the children.<br />

"even" places the child components in the vertical center of the<br />

group, with no additional space added.<br />

• Horizontal — cellVAlign specifies the default horizonal alignment<br />

used by the elements containing the child components. "even"<br />

is the same as "middle" in this case. An individual child component<br />

can override cellVAlign by setting its own valign value. For valign,<br />

see Component Style Attributes.<br />

When specifying cellVAlign, also set the height or width property of the<br />

group, to control how the group takes up the space provided by its container.<br />

For horizontal alignment, set cellAlign instead of cellVAlign.<br />

disabled<br />

groupClass<br />

groupStyle<br />

If true, this group and its children are disabled. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

Name of a CSS style class. When <strong>Zen</strong> lays out this group, it assigns this<br />

value to the HTML class attribute.<br />

String containing a CSS style statement such as:<br />

"color:red; background: yellow;"<br />

When <strong>Zen</strong> lays out this group, it assigns this value to the HTML <br />

style attribute.<br />

labelPosition<br />

layout<br />

Specifies where labels should be displayed for components within this<br />

group. Possible values are "top" and "left". "top" places the labels above<br />

the components; "left" places the labels to the left of the components.<br />

The layout strategy used by this group: "horizontal" or "vertical". If<br />

omitted, the default is vertical.<br />

52 <strong>Using</strong> <strong>Zen</strong>


Template Pages<br />

6.5 Template Pages<br />

You can define an abstract page class that provides the characteristics that you want on all your pages<br />

for the application, then define all application pages as children of the abstract template class. This<br />

would be your template page class:<br />

Class MyApp.TemplatePage Extends %ZEN.Component.page [ Abstract ]<br />

{<br />

/// Class details here<br />

}<br />

All your page classes would look like this:<br />

Class MyApp.AnotherPage Extends MyApp.TemplatePage<br />

{<br />

/// Class details here<br />

}<br />

Template pages offer a convenient way to organize <strong>Zen</strong> applications for a consistent look and feel. To<br />

view an example of this practice, start Studio, and in the SAMPLES namespace, open the page classes<br />

ZENApp.Chart and ZENApp.HelpDesk. Each of these pages inherits from the template page<br />

ZENApp.TemplatePage, which you can also view.<br />

The effect of class inheritance on XData Contents is one of simple replacement. The child class uses<br />

the child XData if it is present, and if not, it uses the parent XData.<br />

Parent Defines<br />

XData Contents<br />

Yes<br />

Yes<br />

No<br />

No<br />

Child Defines<br />

XData Contents<br />

No<br />

Yes<br />

No<br />

Result<br />

Child inherits XData Contents from the parent.<br />

Child uses its own XData Contents definition.<br />

The page is empty.<br />

Inheritance works a bit differently for style. Style involves a cascade of decisions that may coexist<br />

without overriding or replacing each other. Thus, the simple rules for inheritance of XData Contents<br />

are not always true for inheritance of XData Style. To understand how <strong>Zen</strong> applies style, see the next<br />

chapter, <strong>Zen</strong> Style.<br />

<strong>Using</strong> <strong>Zen</strong> 53


<strong>Zen</strong> Layout<br />

6.6 Panes<br />

You can organize your page layout into panes for convenience. A is a specialized group<br />

component with an additional attribute, paneName, that references an XData block outside XData<br />

Contents. At compile time, <strong>Zen</strong> substitutes the appropriate XData block wherever the element<br />

appears in XData Contents.<br />

Consider the following <strong>Zen</strong> page. This sample was introduced at the beginning of this chapter. It<br />

organizes a page into three panes — menuPane, tablePane, and detailPane:<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

My Title<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

The reference to a specific pane looks like this:<br />

<br />

At compile time, <strong>Zen</strong> resolves this reference by finding an XData block in the page class whose name<br />

matches paneName. In the example above, the value of paneName is menuPane, so <strong>Zen</strong> looks for an<br />

XData block called menuPane. <strong>Zen</strong> substitutes this block for the reference. At display time,<br />

whatever is contained within the XData menuPane block appears on the page in the position occupied<br />

by the element . The following is a conceptual view of the result.<br />

54 <strong>Using</strong> <strong>Zen</strong>


Panes<br />

Use of Panes on a <strong>Zen</strong> Page<br />

The following XData block defines the menuPane referenced by the sample :<br />

XData menuPane<br />

{<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

If you are using template pages, you can place a reference in the parent class and allow it to<br />

resolve in either the parent class or the child class. Suppose the reference in the child class is:<br />

<br />

The following table discusses the options for inheritance.<br />

<strong>Using</strong> <strong>Zen</strong> 55


<strong>Zen</strong> Layout<br />

Parent Defines<br />

XData myPane<br />

Yes<br />

Yes<br />

No<br />

No<br />

Child Defines<br />

XData myPane<br />

No<br />

Yes<br />

No<br />

Result<br />

Child inherits XData myPane from the parent.<br />

Child uses its own XData myPane definition. The<br />

parent may reference and allow this reference<br />

to resolve in the child class. This common practice<br />

is illustrated in the ZENApp.HelpDesk sample class.<br />

Any reference to <br />

in either class is ignored.<br />

6.7 Generated HTML<br />

The generated code from XData Contents expresses the <strong>Zen</strong> page as an HTML table, using the standard<br />

HTML elements , , , and . Vertical groups become columns in the table; horizontal<br />

groups become rows. If you are familiar with encoding HTML by hand, you probably recognize this<br />

technique for ensuring the position of items on the page.<br />

<strong>Zen</strong> groups are easy and convenient to set up, and require no coding in HTML. Rather than arranging<br />

HTML , , , and elements into complex nests, all you need to do is place your<br />

<strong>Zen</strong> components into groups. Groups handle all the layout details for you.<br />

56 <strong>Using</strong> <strong>Zen</strong>


7<br />

<strong>Zen</strong> Style<br />

The previous chapter, <strong>Zen</strong> Layout, explained how to place <strong>Zen</strong> components on the page. To do this,<br />

you provide an XData Contents block in the page class and fill it with XML elements that represent<br />

<strong>Zen</strong> components.<br />

This chapter explains how to specify styles for <strong>Zen</strong> components. You can do this by:<br />

• Setting style attributes while placing XML elements in the XData Contents block.<br />

• Applying cascading style sheet (CSS) style definitions in an XData Style block.<br />

• Referencing external CSS files in a variety of ways.<br />

7.1 Component Style Attributes<br />

All <strong>Zen</strong> components provide the XML attributes listed in the following table. These attributes control<br />

how a component behaves within its enclosing group.<br />

Component Style Attributes<br />

Attribute<br />

align<br />

condition<br />

Description<br />

Possible values are "left", "right", or "center". This becomes the align<br />

value for the element that contains the child component in the<br />

generated HTML.<br />

Server-side expression that, if true, allows this component to be<br />

added to the set of page components. This server-only attribute is<br />

not defined on the client side.<br />

<strong>Using</strong> <strong>Zen</strong> 57


<strong>Zen</strong> Style<br />

Attribute<br />

containerStyle<br />

Description<br />

Overrides the parent group’s cellStyle, to provide extra padding or<br />

alignment values for the element that contains the child component<br />

in the generated HTML.<br />

containerStyle is a string containing a CSS style statement such as:<br />

"color:red; background: yellow;"<br />

enclosingClass<br />

enclosingStyle<br />

Name of a CSS style class. When <strong>Zen</strong> lays out this group, it applies<br />

this style to the component’s enclosing element.<br />

String containing a CSS style statement such as:<br />

"color:red; background: yellow;"<br />

When <strong>Zen</strong> lays out this group, it applies this style to the component’s<br />

enclosing element.<br />

height<br />

hidden<br />

id<br />

import<br />

CSS length value (integer or percentage). This becomes the height<br />

value for the element that contains the child component in the<br />

generated HTML.<br />

If true, the component is hidden (placed on the page, but not displayed).<br />

If the status of a component is hidden, its label text (if any)<br />

is also hidden. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

The hidden value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

This value can be used to select a CSS style definition for the<br />

component. It becomes the id value for the component’s enclosing<br />

element.<br />

Comma-separated list of additional component classes that this<br />

component needs to have defined on the client side. Use the full<br />

package and class name for each class in the list. Use import for<br />

cases in which the client needs classes that are not directly defined<br />

in the original object tree. The correct format is as follows:<br />

import="ZENDemo.Component.demoMenu,ZENTest.customComponent"<br />

This server-only attribute is not defined on the client side.<br />

58 <strong>Using</strong> <strong>Zen</strong>


Component Style Attributes<br />

Attribute<br />

label<br />

labelClass<br />

labelStyle<br />

Description<br />

A text label for the component. The component simply supplies the<br />

label text. Displaying this label is the responsibility of the component’s<br />

parent group.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its<br />

text into other languages. See <strong>Zen</strong> Localization.<br />

Name of a CSS style class. When <strong>Zen</strong> lays out this group, it applies<br />

this style to the label displayed for the component.<br />

String containing a CSS style statement such as:<br />

"color:red; background: yellow;"<br />

When <strong>Zen</strong> lays out this group, it applies this style to the label displayed<br />

for the component.<br />

name<br />

slice<br />

title<br />

valign<br />

width<br />

Specifies the name of the component.Typically, this is used to identify<br />

a control within a form. See <strong>Zen</strong> Forms.<br />

Used when this component’s parent group has a cellSize value of<br />

"stretch", slice is an integer value indicating the size of this component<br />

relative to other components within the group. <strong>Zen</strong> computes this<br />

size by dividing this component’s slice value by the sum of all slice<br />

values for all child components in the same group. The minimum<br />

value for slice is 0.<br />

Help text that displays when the user hovers the mouse over this<br />

component (or its label).<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its<br />

text into other languages. See <strong>Zen</strong> Localization.<br />

Possible values are "top", "bottom", or "middle". This becomes the<br />

valign value for the element that contains the child component<br />

in the generated HTML.<br />

CSS length value (integer or percentage). It may be "*" to indicate<br />

that the element should take up the remaining space in the layout<br />

table.This becomes the width value for the element that contains<br />

the child component in the generated HTML.<br />

<strong>Using</strong> <strong>Zen</strong> 59


<strong>Zen</strong> Style<br />

You can apply component style attributes while placing the component in the XData Contents block.<br />

The following example applies the style attributes valign, height, and width to the <strong>Zen</strong> components<br />

and :<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

My Title<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

7.2 Enclosing Element<br />

To facilitate use of CSS styles as well as dynamic HTML, every <strong>Zen</strong> component that you place on a<br />

<strong>Zen</strong> page is enclosed within an element on the generated HTML page. This is the enclosing<br />

for the component.<br />

If you have assigned a specific value to the component’s id attribute, this becomes the HTML id of<br />

the enclosing . This convention makes it possible to directly select the enclosing element from<br />

a CSS style sheet. For example, suppose you define a button as follows:<br />

<br />

You could then used the following CSS definition in your page’s XData Style block, to set the color<br />

of this button:<br />

XData Style<br />

{<br />

<br />

#myButton input {<br />

color: red;<br />

}<br />

<br />

}<br />

It is also possible to work with a component’s enclosing programmatically. Every component<br />

has a client-side getEnclosingDiv method that returns the HTML element that <strong>Zen</strong> is using as<br />

the component’s enclosing . For example:<br />

60 <strong>Using</strong> <strong>Zen</strong>


XData Style<br />

Method GiveMyButtonStyleToAbc() [ Language = javascript ]<br />

{<br />

var comp = zenPage.getComponentById('abc');<br />

var div = comp.getEnclosingDiv();<br />

}<br />

// div is an HTML div element<br />

div.className = 'myButton';<br />

7.3 XData Style<br />

Any <strong>Zen</strong> component class, page class, or application class can provide an XData Style block to define<br />

CSS styles. The <strong>Zen</strong> Tutorial chapter introduced XData Style when it displayed the skeleton class<br />

generated by the New <strong>Zen</strong> Application wizard, as follows:<br />

/// This is my first new <strong>Zen</strong> application.<br />

Class MyApp.MyNewApp Extends %ZEN.application<br />

{<br />

}<br />

/// This is the name of this application.<br />

Parameter APPLICATIONNAME = "My New <strong>Zen</strong> Application";<br />

/// This is the URL of the main starting page of this application.<br />

Parameter HOMEPAGE = "";<br />

/// This Style block contains application-wide CSS style definitions.<br />

XData Style<br />

{<br />

<br />

<br />

}<br />

To define styles for the application class shown above, you would add CSS statements between the<br />

tag and the closing tag.<br />

The following example shows an XData Style block in a page class. This class defines styles in the<br />

XData Style block and then references them from XData Contents by using the id attribute with components.<br />

The following example defines and then references the styles title, vg1, and vg2.<br />

<strong>Using</strong> <strong>Zen</strong> 61


<strong>Zen</strong> Style<br />

/// My very first <strong>Zen</strong> page class.<br />

Class MyApp.MyNewPage Extends %ZEN.Component.page<br />

{<br />

}<br />

/// Class name of application this page belongs to.<br />

Parameter APPLICATION = "MyApp.MyNewApp";<br />

/// Displayed name of this page.<br />

Parameter PAGENAME = "My Home Page";<br />

/// Domain used for localization.<br />

Parameter DOMAIN = "";<br />

/// This Style block contains page-specific CSS style definitions.<br />

XData Style<br />

{<br />

<br />

/* style for title bar */<br />

#title {<br />

background: #C5D6D6;<br />

color: black;<br />

font-family: Verdana;<br />

font-size: 1.5em;<br />

font-weight: bold;<br />

padding: 5px;<br />

border-bottom: 1px solid black;<br />

text-align: center;<br />

}<br />

}<br />

#vg1 {<br />

border-right: 1px solid black;<br />

background: #E0E0FF;<br />

height: 600px;<br />

}<br />

#vg2 {<br />

}<br />

<br />

/// This XML block defines the contents of this page.<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

Title<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

7.4 Inheritance of Styles<br />

The effect of class inheritance on XData Style is one of simple replacement.<br />

62 <strong>Using</strong> <strong>Zen</strong>


Cascade of Styles<br />

Parent Defines<br />

XData Style<br />

Yes<br />

Yes<br />

No<br />

No<br />

Child Defines<br />

XData Style<br />

No<br />

Yes<br />

No<br />

Result<br />

Child inherits XData Style from the parent.<br />

Child uses its own XData Style definition.<br />

Some parent of both classes probably defines XData<br />

Style. If not, the browser applies its own style<br />

defaults.<br />

A class that inherits from another class overrides its parent’s XData Style. Thus, a custom component<br />

that provides XData Style overrides the XData Style in the base component class. A page class that<br />

provides XData Style overrides the XData Style in its template page class.<br />

However, this behavior does not cross over the boundaries of class inheritance. A is a component,<br />

but no component actually inherits from . So a component that appears on a page within<br />

an application does not override the XData Style block in either the page class or the application class.<br />

The XData Style blocks provided by the component class, page class, and application class all coexist,<br />

subject to the rules described in the next topic, Cascade of Styles.<br />

7.5 Cascade of Styles<br />

When a <strong>Zen</strong> page constructs itself, it collects all the CSS style information that you have provided for<br />

each component on the page, and applies it to the component. There may be many sources for this<br />

information: page classes, application classes, and component classes. <strong>Zen</strong> applies the information in<br />

these sources in the following order. Note that when conflicts exist, the styles that are defined last take<br />

precedence:<br />

1. Styles defined by the CSS file for the <strong>Zen</strong> component library, ZEN_Component.css<br />

2. Styles defined by base component classes.<br />

The default styles for the built-in <strong>Zen</strong> components are provided via an XData Style block in the<br />

corresponding %ZEN.Component class (or one of its parents). However, if you want to change<br />

the style of a built-in <strong>Zen</strong> component, do not edit the class directly. Either subclass the component<br />

to create a custom component, or override the corresponding style definitions in the page or<br />

application class.<br />

3. Styles defined by subclasses of base component classes (that is, custom components).<br />

<strong>Using</strong> <strong>Zen</strong> 63


<strong>Zen</strong> Style<br />

Any subclass of %ZEN.Component.component can provide an XData Style block. If the child has<br />

an XData Style block, this replaces the XData Style from the parent class. If not, the child inherits<br />

XData Style from the parent.<br />

4. Styles defined within the application class for the current application. These may come from any<br />

of the following sources. Styles from each source are evaluated in the sequential order as shown:<br />

• An XData Style block containing CSS statements<br />

• A reference to an external CSS file using the CSSINCLUDES parameter.<br />

5. Styles defined within the template page class (if there is one for the current page). These may<br />

come from any of the following sources. Styles from each source are evaluated in the sequential<br />

order as shown:<br />

• A reference to an external CSS file using the CSSINCLUDES parameter<br />

• An XData Style block containing CSS statements<br />

• Style attributes in XData Contents. For an individual component, these may provide:<br />

- Simple values for HTML attributes, such as "300" for height<br />

- Literal CSS statements, such as "color:red; background: yellow;")<br />

- The name of a CSS style that is defined somewhere in the cascade of styles<br />

6. Styles defined within the page class. For example:<br />

• A reference to an external CSS file using the CSSINCLUDES parameter<br />

• An XData Style block containing CSS statements<br />

• Style attributes in XData Contents. For an individual component, these may provide:<br />

- Simple values for HTML attributes, such as "300" for height<br />

- Literal CSS statements, such as "color:red; background: yellow;")<br />

- The name of a CSS style that is defined somewhere in the cascade of styles<br />

Thus, when it comes to style, “page” overrides “application” overrides “component.” Within each of<br />

these categories, “child” overrides “parent.”<br />

64 <strong>Using</strong> <strong>Zen</strong>


Overriding Built-in Styles<br />

Cascade of Style Definitions<br />

This order of precedence makes it easier to ensure a consistent “look and feel” for your application.<br />

You can override the style definition within the application class (for an application-wide style override),<br />

within a template page class (to override a value for a suite of pages) or within an ordinary page class<br />

(to override a value for a specific page).<br />

However, it is important to note that this order of precedence does not exactly match the hierarchy of<br />

these objects when ZEN constructs the page for display. Compare this discussion and diagram with<br />

the chapter <strong>Zen</strong> Application Concepts, topic <strong>Zen</strong> Applications.<br />

7.6 Overriding Built-in Styles<br />

Suppose you want to override the style of a built-in <strong>Zen</strong> component such as . There is no<br />

requirement to do this, but once you get your table onto the page, you might discover that you want<br />

to change its appearance. If so, you must override the CSS styles for . To accomplish this,<br />

you need to know:<br />

• The name of the CSS style definition that you want to change<br />

• Where, in the cascade of styles, you want to interject changes to this style<br />

<strong>Using</strong> <strong>Zen</strong> 65


<strong>Zen</strong> Style<br />

• Which technique you want to use to apply changes to the style:<br />

- Referencing an external CSS file from a <strong>Zen</strong> class<br />

- Providing an XData Style block in a <strong>Zen</strong> class<br />

The following XData Style block changes the background color, border style, and font family choices<br />

for a CSS rule called table.tpTable. How did the developer choose this rule to change How does<br />

this XData Style block fit into the cascade of styles And why did the developer choose to provide an<br />

XData Style block rather than an external CSS file The next several topics provide answers.<br />

XData Style<br />

{<br />

<br />

table.tpTable {<br />

background: green;<br />

border: 1px solid red;<br />

font-family: courier new;<br />

}<br />

<br />

}<br />

7.6.1 Finding the CSS Style Name<br />

You can determine which CSS rules to override for a specific <strong>Zen</strong> component as follows:<br />

1. Somewhere in the inheritance tree for each <strong>Zen</strong> component, there is an XData Style block that<br />

defines the CSS rules for this component. To find the correct one, usually you must know something<br />

about the inheritance of the component class. For example, %ZEN.Component.tablePane inherits<br />

from %ZEN.Component.simpleTablePane. It is the simpleTablePane class that contains the relevant<br />

XData Style block. There is no XData Style block in the tablePane class.<br />

You can use the online class documentation to trace inheritance. Start the documentation in one<br />

of the following ways:<br />

• From Studio, choose Tools > Class Browser. Under the %ZEN.Component package, find the<br />

class you are interested in. Right-click on the class name and choose <strong>Documentation</strong>.<br />

• Start the <strong>InterSystems</strong> online documentation. Scroll to the bottom of the documentation home<br />

page and choose Class Reference Information. Choose the %SYS namespace and<br />

%ZEN.Component package. Click on the class name.<br />

Once you have found the documentation page for the class of interest, see if it inherits from another<br />

<strong>Zen</strong> component class. If so, the XData Style block is probably in the parent class. You can click<br />

on the parent class name to navigate to its documentation page.<br />

2. When you know the class name of the component you want to research, you need to view its CSS<br />

style definitions. You can do this in one of the following ways:<br />

66 <strong>Using</strong> <strong>Zen</strong>


• In Studio, run the <strong>Zen</strong> Style Wizard to see if the component or its parent are listed. The <strong>Zen</strong><br />

Style Wizard is the easiest way to modify styles. It does not include every style, but lists the<br />

most popular styles for modification. simpleTablePane is there, with the entry:<br />

table.tpTable<br />

Described as:<br />

Main table for tablePane<br />

• In Studio, in the %SYS namespace and %ZEN.Component package, open the component class<br />

for viewing. Find its XData Style block or that of its parent, and see what CSS rules it contains.<br />

• Examine the CSS file for the <strong>Zen</strong> component library. The file is located as follows, where<br />

C:\CacheSys is the name of your installation directory:<br />

C:\CacheSys\CSP\broker\ZEN_Component.css<br />

Search for the component name in the code comments. The styles that follow (until the next<br />

component name) are those for the component. For example:<br />

/* %ZEN.Component.simpleTablePane */<br />

/* table */<br />

table.tpTable {<br />

background: white;;<br />

border: 1px solid black;<br />

font-family: arial;<br />

width: 100%;<br />

table-layout: fixed;<br />

empty-cells: show;<br />

}<br />

/* ...etc... */<br />

Overriding Built-in Styles<br />

7.6.2 Overriding a CSS Style Rule<br />

Once you have found the CSS rule that applies to the component whose appearance you want to<br />

modify, you can override the CSS rule in one of two ways:<br />

• Referencing an external CSS file from a <strong>Zen</strong> application, or page class<br />

• Providing an XData Style block in a <strong>Zen</strong> application, page, or custom component class<br />

To effectively predict the results of your changes, keep in mind the order of precedence rules described<br />

in the previous topic, Cascade of Styles. The following table restates these rules in terms of the results<br />

that you are trying to accomplish.<br />

<strong>Using</strong> <strong>Zen</strong> 67


<strong>Zen</strong> Style<br />

Where and How to Override Built-in Styles<br />

What to Accomplish<br />

Application-wide<br />

styling rules. You can<br />

override these styles<br />

in template pages or<br />

in individual page<br />

classes.<br />

Styles that apply to a<br />

group of pages within<br />

an application. You<br />

can override these<br />

styles in individual<br />

page classes.<br />

Where to Interject Style Changes<br />

Place the revised CSS rule in an external CSS file and reference<br />

from the application class using the CSSINCLUDES class<br />

parameter. The value of CSSINCLUDES can be a<br />

comma-separated list of multiple CSS files.<br />

Place an XData Style block in the application class and place<br />

the revised CSS rule definition within it.You can either type rule<br />

syntax into XData Style or use the <strong>Zen</strong> Style Wizard for<br />

convenient style editing. If there are style conflicts between XData<br />

Style and CSSINCLUDES for the application, XData Style takes<br />

precedence.<br />

Create a template page class. Ensure that all the pages you want<br />

to have consistent style are subclasses of this template page.<br />

Place the revised CSS rule in an external CSS file and reference<br />

from the template page class using the CSSINCLUDES class<br />

parameter. The value of CSSINCLUDES can be a<br />

comma-separated list of multiple CSS files.<br />

Place an XData Style block in the template page class and place<br />

the revised CSS rule definition within it.You can either type rule<br />

syntax into XData Style or use the <strong>Zen</strong> Style Wizard for<br />

convenient style editing. If there are style conflicts between XData<br />

Style and CSSINCLUDES for the template page class, XData<br />

Style takes precedence.<br />

Styles that apply to<br />

only one page within<br />

an application.<br />

Place the revised CSS rule in an external CSS file and reference<br />

from the page class using the CSSINCLUDES class parameter.<br />

The value of CSSINCLUDES can be a comma-separated list of<br />

multiple CSS files.<br />

Place an XData Style block in the page class and place the<br />

revised CSS rule definition within it. You can either type rule<br />

syntax into XData Style or use the <strong>Zen</strong> Style Wizard for<br />

convenient style editing. If there are style conflicts between XData<br />

Style and CSSINCLUDES for the page class, XData Style takes<br />

precedence.<br />

68 <strong>Using</strong> <strong>Zen</strong>


Applying New Styles<br />

What to Accomplish<br />

Styles that apply to<br />

all instances of a<br />

particular component.<br />

Where to Interject Style Changes<br />

Any styles defined in application or page classes automatically<br />

override styles defined in component classes, so for stylistic<br />

consistency and control you should make changes near the end<br />

of the cascade, in the application or page class, rather than in<br />

the component class.<br />

However, if you wish, you may create a custom components that<br />

is a subclass of the built-in <strong>Zen</strong> component whose styles you<br />

wish to change. Place an XData Style block in the custom<br />

component class and place the revised CSS rule definition within<br />

this XData Style.You can either type rule syntax into XData Style<br />

or use the <strong>Zen</strong> Style Wizard for convenient style editing.<br />

In any case, do not edit the XData Style block in a built-in <strong>Zen</strong><br />

component class or its parent. Do not edit the built-in stylesheet<br />

ZEN_Component.css. Changes of this kind will be lost next time<br />

you upgrade the Caché server version.<br />

7.7 Applying New Styles<br />

The above topics explain how to modify styles that are already in use by a built-in <strong>Zen</strong> component. If<br />

you want to define an entirely new CSS style (with a new name) and apply that style to a component,<br />

there are additional steps to perform. In that case you must not only subclass the component and define<br />

the CSS style, but also reference that CSS style from the portion of the subclass that renders the component<br />

on the page as HTML. A later chapter, Custom Components, covers these steps in detail.<br />

<strong>Using</strong> <strong>Zen</strong> 69


8<br />

<strong>Zen</strong> Tables<br />

A <strong>Zen</strong> table is data-driven. It takes the resultset returned by an SQL query and displays it as an HTML<br />

table. There are a number of ways to generate the resultset for a <strong>Zen</strong> table. You can specify an SQL<br />

statement, reference a pre-defined SQL query, or provide <strong>Zen</strong> with the inputs it needs to generate an<br />

SQL query for you.<br />

Once you have the data, you can style the resulting table in any way you wish. The following figure<br />

shows a simple example. This table uses “zebra” patterning for alternate rows. The user has entered<br />

data in the table header to filter the results that the table displays. In this case, the user has selected<br />

only entries whose names begin with X, with Active status, who are also Assistants.<br />

This chapter explains how to work with <strong>Zen</strong> tables as follows:<br />

• How to place a table on a <strong>Zen</strong> page<br />

• How to work with the table programmatically after it is on the <strong>Zen</strong> page<br />

• How to identify the data source for a <strong>Zen</strong> table<br />

<strong>Using</strong> <strong>Zen</strong> 71


<strong>Zen</strong> Tables<br />

• How to supply parameters for the table query, if needed<br />

• How to specify column details, including filters and links<br />

• General style properties that <strong>Zen</strong> tables can have<br />

• How to define data-specific styling for rows and columns<br />

• How snapshot mode supports multipage tables and simplifies refresh operations<br />

• How a <strong>Zen</strong> table handles user interactions<br />

• What happens during table refresh operations, and how to request them<br />

8.1 <br />

is the XML projection of the versatile %ZEN.Component.tablePane class. To place a table<br />

on a <strong>Zen</strong> page, place a component inside the page class XData Contents block.<br />

As you read this chapter, you will encounter descriptions of the various component and auxiliary<br />

classes that <strong>Zen</strong> supplies to support tables. The following list summarizes the XML elements that you<br />

will use to represent these classes in XData Contents. The most important of these is :<br />

• — Draws an HTML table based on an SQL query. Each row in the resultset is displayed<br />

as a row in the table. A may contain the following elements, as needed:<br />

- — Each element provides one of the parameters required to construct<br />

the query.<br />

- — Each element specifies layout, style, and behavior details for a particular<br />

column in the resulting table. elements are optional when all columns in<br />

the resultset are displayed. However, sometimes a needs to select which of the<br />

columns in the resultset should be displayed. When this is the case, elements are<br />

required.<br />

- — Each element defines one data-specific detail that applies to<br />

rows and cells within the table. For example, cells that contain a certain value might display<br />

a certain background color, such as red to indicate an error condition. The specific cells that<br />

contain this value might be different each time the table refreshes; <strong>Zen</strong> keeps track of these<br />

details for you and colors all cells appropriately.<br />

• — Automatically provides a standard set of buttons for moving through the<br />

pages of a multipage table.<br />

• — An alternative to , this element provides extra buttons<br />

to help users navigate large, multipage tables.<br />

72 <strong>Using</strong> <strong>Zen</strong>


Data Sources<br />

has the following general-purpose attributes.<br />

Attribute<br />

dataSource<br />

Description<br />

Specifies which columns from the %ResultSet to display, and in what order.<br />

Possible values are:<br />

• "query" — All columns referenced by the query appear, in order from<br />

left to right.<br />

• "columns" — Only the columns explicitly defined as entries<br />

within the appear, in order from left to right.<br />

When you omit dataSource from the , <strong>Zen</strong> uses the value<br />

"query" by default, unless there are entries defined, in which<br />

case <strong>Zen</strong> ignores any dataSource value and uses "columns".<br />

initialExecute<br />

If initialExecute is true, the query associated with this is<br />

executed when the table is first displayed. Otherwise the <br />

will execute the query only on demand. The default is true.<br />

initialExecute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

offers many additional attributes that you can use to configure layout, style, and behavior.<br />

The following topics describe them.<br />

8.2 Data Sources<br />

A element must indicate a data source for the table in one of the following ways:<br />

• Specifying an SQL statement<br />

• Providing a simple description that <strong>Zen</strong> uses to generate an SQL statement<br />

• Referencing a class query that generates an SQL statement<br />

• Referencing a callback method that generates an SQL statement<br />

The following topics describe each option in detail. Regardless of which option you use, all techniques<br />

support the maxRows attribute. It controls the size of the data returned.<br />

<strong>Using</strong> <strong>Zen</strong> 73


<strong>Zen</strong> Tables<br />

Attribute<br />

maxRows<br />

Description<br />

The maximum number of rows to fetch. For ordinary tables this is the<br />

maximum number of rows to display. For snapshot tables, maxRows is<br />

the maximum size of the snapshot and pageSize is the number of rows to<br />

display per page. The default value for maxRows is 100.<br />

8.2.1 Specifying an SQL Query<br />

A can provide a complete SQL statement as the value of its sql attribute. <strong>Zen</strong> executes<br />

this SQL statement to provide the contents of the table.<br />

The following is an example of a simple SQL statement:<br />

<br />

You may provide any input parameter values using elements inside the .<br />

The attribute is the XML projection of the %ZEN.Component.tablePane property sql.<br />

Unlike most other %ZEN.Component.tablePane properties, the sql property cannot be set from the<br />

client at runtime. It can only be set from XData Contents. This is because sql is an encrypted attribute.<br />

The sqlvalue is encrypted (using the current session key) when it is sent to the client. If this value is<br />

returned to the server, it is automatically decrypted.<br />

This prevents users from seeing the definition of an SQL statement if they view page source within<br />

their browser and prevents client logic from constructing arbitrary queries. For security reasons, query<br />

activities should always be restricted to the server.<br />

8.2.2 Generating an SQL Query<br />

Constructing SQL queries can be tedious, so the supports attributes that allow you to<br />

automatically generate the query based on a simple description. Basically, this is similar to using a<br />

callback method (as described in a later topic) except that <strong>Zen</strong> generates the callback method for you,<br />

based on your description of the query.<br />

Attribute<br />

groupByClause<br />

Description<br />

(Optional) An SQL GROUP BY clause such as "Year,State". The<br />

groupByClause value can be a literal string, or it can contain a <strong>Zen</strong><br />

#()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

74 <strong>Using</strong> <strong>Zen</strong>


Data Sources<br />

Attribute<br />

orderByClause<br />

tableName<br />

whereClause<br />

Description<br />

(Optional) An SQL ORDER BY clause such as "Name,State". If not<br />

provided, then whenever the user clicks on a column header, the next<br />

query contains the appropriate ORDER BY clause based on the user’s<br />

choice. The orderByClause value can be a literal string, or it can<br />

contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

The name of the SQL table that provides the data for the table. This<br />

value is used in the FROM clause for the generated query. The<br />

tableName value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

(Optional) An SQL WHERE clause such as "Name='Elvis'". If not<br />

provided, then if any column filters are defined in this table, a WHERE<br />

clause is created based on the current filter values. The whereClause<br />

value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

To have the generate an SQL query, you must do the following:<br />

1. Provide a value for the tableName attribute.<br />

2. Do not provide values for the sql, queryClass, queryName, or OnCreateResultSet. All of these<br />

attributes take precedence over the behavior described in this topic.<br />

After you satisfy the first two conditions, <strong>Zen</strong> assumes a "columns" value for dataSource.<br />

3. Define the names of one or more columns by providing elements inside the .<br />

There must be at least one column defined or a “Missing SELECT list” error will result.<br />

4. You can add query parameters by providing elements inside the .<br />

5. You can add clauses for the generated query by providing the attributes<br />

groupByClause, orderByClause, or whereClause, or by allowing defaults to prevail as described<br />

in the table above.<br />

The following is a simple example:<br />

<br />

<br />

<br />

<br />

This example generates an SQL statement similar to the following:<br />

SELECT ID,Name FROM MyApp.Employee<br />

<strong>Using</strong> <strong>Zen</strong> 75


<strong>Zen</strong> Tables<br />

<strong>Zen</strong> executes this query to provide the contents of the table. In the example, the ID column is marked<br />

as hidden. This means that its value is fetched (it can be used for conditions or actions) but not displayed.<br />

For details about hidden and other attributes, see the Table Columns topic.<br />

Note:<br />

A generated SQL query can be useful for tables with column filters.<br />

8.2.3 Referencing a Class Query<br />

A can reference a pre-existing class query to obtain a %ResultSet object. The following<br />

attributes support this approach.<br />

Attribute<br />

queryClass<br />

queryName<br />

Description<br />

The name of the class containing the query.You must also provide a value<br />

for queryName.<br />

The name of the class query that will provide the %ResultSet for this<br />

. You must also provide a value for queryClass.<br />

You may provide any input parameter values for the query by placing elements inside<br />

the . For example:<br />

<br />

<br />

<br />

<br />

8.2.4 <strong>Using</strong> a Callback Method<br />

A can generate a table using an application-defined %ResultSet object. The following<br />

attributes support this approach.<br />

76 <strong>Using</strong> <strong>Zen</strong>


Data Sources<br />

Attribute<br />

OnCreateResultSet<br />

OnExecuteResultSet<br />

showQuery<br />

Description<br />

The name of a server-side callback method to call to create a<br />

%ResultSet object. The OnCreateResultSet value must be the<br />

name of a server-only method defined in the page class whose<br />

XData Contents references the component.<br />

The name of a server-side callback method to call to execute the<br />

%ResultSet object returned by the method identified by<br />

OnCreateResultSet. The OnExecuteResultSet value must be the<br />

name of a server-only method defined in the page class whose<br />

XData Contents references the component.<br />

showQuery works only if a callback method is used to generate<br />

the table, and only if this method sets the queryText property of the<br />

QueryInfo object to contain the text of the query. The next topic,<br />

Data Sources, explains the details. Of the various components<br />

that use callback methods to generate SQL queries, only<br />

and support the showQuery attribute.<br />

If showQuery is true, the <strong>Zen</strong> page displays the SQL query used<br />

to provide the contents of the or <br />

component. This is useful for troubleshooting purposes, during<br />

application development. The default showQuery value is false.<br />

showQuery has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

The showQuery value can be a literal string, or it can contain a<br />

<strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

Consider the following example:<br />

<br />

The corresponding server-side callback method is defined within the page class as follows. The callback<br />

method must return a new instance of %ResultSet object that is executed and processed by the tablePane.<br />

It must also return a status code by reference to indicate if there were any errors encountered in creating<br />

the %ResultSet object.<br />

Method CreateRS(Output pSC As %Status,<br />

pInfo As %ZEN.Auxiliary.QueryInfo) As %ResultSet<br />

{<br />

Set pSC = $$$OK<br />

Set tRS = ##class(%ResultSet).%New()<br />

// ... method activities here ...<br />

Quit tRS<br />

}<br />

<strong>Using</strong> <strong>Zen</strong> 77


<strong>Zen</strong> Tables<br />

As you can see from the method signature in the example above, the callback method receives information<br />

from the tablePane class via a %ZEN.Auxiliary.QueryInfo object; some information is also passed<br />

back via this object. For details about this object, see the following table.<br />

QueryInfo Properties<br />

Property<br />

columnExpression<br />

columns<br />

filterOps<br />

filters<br />

filterTypes<br />

groupByClause<br />

orderByClause<br />

parms<br />

queryExecuted<br />

queryText<br />

Description<br />

The colExpression values from each in the .<br />

columnExpression organizes these values as a multidimensional array<br />

subscripted by colName.<br />

The colName values from each in the .<br />

columns organizes these values as a multidimensional array<br />

subscripted by column number (1–based).<br />

The filterOp values from each in the . filterOps<br />

organizes these values as a multidimensional array subscripted by<br />

colName.<br />

The filterValue values from each in the .<br />

filters organizes these values as a multidimensional array subscripted<br />

by colName.<br />

The filterType values from each in the .<br />

filterTypes organizes these values as a multidimensional array<br />

subscripted by by colName.<br />

The groupByClause value for the , if supplied.<br />

The orderByClause value for the , if supplied.<br />

Multidimensional array, subscripted by parameter number (1–based).<br />

This array contains any input values provided by <br />

elements within the .<br />

Set this property to true in the method identified by<br />

OnCreateResultSet, to indicate that the newly created %ResultSet<br />

has already been executed and you do not want the method<br />

identified by OnExecuteResultSet to be called. The default is false.<br />

The method identified by OnCreateResultSet can set this value to<br />

the actual query text, to be displayed if the showQuery value is true.<br />

78 <strong>Using</strong> <strong>Zen</strong>


Data Sources<br />

Property<br />

rowCount<br />

Description<br />

If this value is set by the callback, upon return the rowCount property<br />

contains the number of rows returned by the query. After the query<br />

is executed, rowCount could be different from rows.<br />

Note that rowCount is a string, and not numeric, as its value might<br />

be "" or "100+". Any number of rows greater than 100 is represented<br />

as "100+". When testing rowCount from JavaScript, if you<br />

want to convert to a numeric value use parseInt for base 10:<br />

rowCount = parseInt(rowCount,10);<br />

rows<br />

sortColumn<br />

sortOrder<br />

tableName<br />

whereClause<br />

The number of rows requested. For tables, this is the maxRows<br />

value.<br />

The colName of the current sort column selected by the user.<br />

The table’s current sort order (usually determined by user clicks)<br />

such as "asc" or "desc".<br />

The tableName value.<br />

The whereClause value for the , if supplied.<br />

Just like tablePane, the control components dataCombo and dataListBox can also use a callback method<br />

to generate a %ResultSet. repeatingGroup can do this as well. Some of the properties in the QueryInfo<br />

object apply only to tablePane queries. dataCombo, dataListBox, and repeatingGroup ignore any tableonly<br />

properties, including those for columns, filters, and sorting. Only tablePane and dataCombo<br />

support queryText.<br />

The following is a more detailed example of using a callback method to create a %ResultSet. The<br />

callback method constructs a dynamic SQL statement in response to current values of tablePane<br />

properties sortOrder and sortColumn. The tablePane automatically passes these values to the callback<br />

method as the corresponding properties of the input %ZEN.Auxiliary.QueryInfo object.<br />

Also note how the method places the SQL statement text in the queryText property of QueryInfo before<br />

exiting. If the showQuery value is true, this table will display itself, plus the query that<br />

generated it.<br />

<strong>Using</strong> <strong>Zen</strong> 79


<strong>Zen</strong> Tables<br />

Method CreateRS(Output tSC As %Status,<br />

pInfo As %ZEN.Auxiliary.QueryInfo) As %ResultSet<br />

{<br />

Set tRS = ""<br />

Set tSC = $$$OK<br />

Set tSELECT = "ID,Name,Title"<br />

Set tFROM = "MyApp.Employee"<br />

Set tORDERBY = pInfo.sortColumn<br />

Set tSORTORDER = pInfo.sortOrder<br />

Set tWHERE = ""<br />

// Build WHERE clause based on filters<br />

If ($GET(pInfo.filters("Name"))'="") {<br />

Set tWHERE = tWHERE _ $SELECT(tWHERE="":"",1:" AND ") _<br />

"Name %STARTSWITH '" _ pInfo.filters("Name") _ "'"<br />

}<br />

If ($GET(pInfo.filters("Title"))'="") {<br />

Set tWHERE = tWHERE _ $SELECT(tWHERE="":"",1:" AND ") _<br />

"Title %STARTSWITH '" _ pInfo.filters("Title") _ "'"<br />

}<br />

Set sql = "SELECT " _ tSELECT _ " FROM " _ tFROM<br />

Set:tWHERE'="" sql = sql _ " WHERE " _tWHERE<br />

Set:tORDERBY'="" sql =<br />

sql _ " ORDER BY " _tORDERBY _ $SELECT(tSORTORDER="desc":" desc",1:"")<br />

Set tRS = ##class(%ResultSet).%New()<br />

Set tSC = tRS.Prepare(sql)<br />

Set pInfo.queryText = sql<br />

}<br />

Quit tRS<br />

8.3 Query Parameters<br />

When you are working with SQL queries to generate the data for a <strong>Zen</strong> table, you sometimes need to<br />

provide values for query input parameters, defined as characters within the query. To do this, use<br />

elements within the element.<br />

Attribute<br />

value<br />

Description<br />

Specifies the parameter value:<br />

<br />

The value supplied for a parameter can be a literal string, or it can contain<br />

a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

Previous topics showed examples of using the element, including the following class<br />

query example:<br />

80 <strong>Using</strong> <strong>Zen</strong>


Table Columns<br />

<br />

<br />

<br />

<br />

When you work with %ZEN.Component.tablePane programmatically, you work with <br />

elements as members of the tablePane parameters property, a list collection. Each in the<br />

becomes a member of the parameters collection in tablePane, associated with an ordinal<br />

position: 1, 2, 3, etc.<br />

You can change the value of query parameters at runtime, from the client, by setting values in the<br />

parameters collection property of the tablePane object. The following example changes the value of<br />

the first parameter to Finance, re-executes the query on the server, and updates the contents of the<br />

tablePane to display the new results:<br />

Method changeParams() [ Language = javascript ]<br />

{<br />

// find the tablePane component<br />

var table = this.getComponentById('table');<br />

table.setProperty('parameters',1,'Finance');<br />

}<br />

8.4 Table Columns<br />

Previous topics explained that draws an HTML table based on an SQL query. Each row<br />

in the query resultset is displayed as a row in the table. A may also contain one or more<br />

elements. These select which of the columns in the query resultset should be displayed in<br />

the table. elements also specify layout, style, and behavior for each column.<br />

Previous topics showed several examples of using the element, including the following<br />

example, in which elements help <strong>Zen</strong> to automatically construct an SQL query:<br />

<br />

<br />

<br />

<br />

<br />

The element is the XML projection of the %ZEN.Auxiliary.column class. supports<br />

the general-purpose attributes described in the following table.<br />

<strong>Using</strong> <strong>Zen</strong> 81


<strong>Zen</strong> Tables<br />

Attribute<br />

cellTitle<br />

colExpression<br />

colName<br />

header<br />

hidden<br />

OnDrawCell<br />

seed<br />

Description<br />

Text specifying the tooltip message for any cell within the column.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

If the table is automatically constructing an SQL query, this is the SQL<br />

expression used to get the value of this column. For example:<br />

colExpression="Customer->Name"<br />

The name of the SQL data column that this column is associated with.<br />

The colName value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

If not specified, the column is displayed without a data value. Typically<br />

this technique is used to display a link action in a row.<br />

Text specifying the column header.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

The header value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

If true, this column is not be displayed. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

The hidden value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

The name of a server-side callback method that provides HTML content<br />

for cells within this column. If defined, this callback is invoked on the<br />

server when this component is drawn. It provides HTML content by using<br />

&html or the WRITE command.<br />

The OnDrawCell value must be the name of a server-only method defined<br />

in the page class whose XData Contents references the <br />

component.<br />

Allows you to pass some arbitrary value to the OnDrawCell callback.<br />

82 <strong>Using</strong> <strong>Zen</strong>


Table Style<br />

Attribute<br />

style<br />

title<br />

width<br />

Description<br />

CSS style value to be applied to the cells (HTML elements) within<br />

this column. For example: "color: red;"<br />

The style value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

Text specifying the tooltip displayed when the user moves the mouse<br />

over the column header.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

The HTML style value for <strong>Zen</strong> tables is "fixed". This means that each<br />

column has a specific width value in the generated HTML page. <strong>Zen</strong><br />

determines these values as follows:<br />

• You can specify a width value for any column.<br />

• If you do not specify a width, <strong>Zen</strong> assigns a width that is proportional<br />

to the size of the contents of that column (relative to other columns<br />

in the table).<br />

The width value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

also provides attributes that support dynamic filtering, linking, and sorting of the <strong>Zen</strong> table.<br />

Later topics describe these special-purpose attributes.<br />

When you work with %ZEN.Component.tablePane programmatically, you work with elements<br />

as members of the tablePane columns property, a list collection of %ZEN.Auxiliary.column objects.<br />

Each in the becomes a member of the columns collection in tablePane, associated<br />

with its ordinal position: 1, 2, 3, etc.<br />

8.5 Table Style<br />

offers the following attributes to control the general style of the table.<br />

<strong>Using</strong> <strong>Zen</strong> 83


<strong>Zen</strong> Tables<br />

Attribute<br />

caption<br />

extraColumnWidth<br />

fixedHeaders<br />

bodyHeight<br />

nowrap<br />

showRowNumbers<br />

showValueInTooltip<br />

Description<br />

Text specifying the caption to display for this table.<br />

Although you enter ordinary text for this attribute, it has the<br />

underlying data type %ZEN.Datatype.caption. This makes it easy to<br />

localize its text into other languages. See <strong>Zen</strong> Localization.<br />

The HTML width to allow for extra columns, such as when multiple<br />

rows are selected or row numbers are displayed in the tablePane.<br />

The default width for an extra column is 30.<br />

If true, the header of the table will stay in position when the body<br />

of the table is scrolled. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

If fixedHeaders is true, bodyHeight provides an HTML length value<br />

that specifies the height of the body section of the table. The<br />

default bodyHeight is "20.0em".<br />

If true, table cells disallow word wrapping. If false, they allow it.<br />

The default is true.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

If true, display a row number column on the left-side of the<br />

tablePane. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

If true, the tooltip (HTML title attribute) displayed for cells within<br />

the table consists of the current value of the cell. The default is<br />

false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

84 <strong>Using</strong> <strong>Zen</strong>


Conditional Style for Rows or Cells<br />

Attribute<br />

showZebra<br />

Description<br />

If true, use zebra striping (alternating dark and light rows) to display<br />

the tablePane. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

8.6 Conditional Style for Rows or Cells<br />

A may contain one or more elements. Each is a simple expression,<br />

based on the values of a given row, that controls the style of the row or of an individual cell within<br />

the row. For example:<br />

<br />

<br />

<br />

In the above example, every row in which the value of the Name column starts with “A” will be displayed<br />

with a plum background.<br />

Typically, the conditional style mechanism is used to highlight rows or cells containing special values<br />

(such as out-of-range or error cases). Adding conditions does increase the amount of processing needed<br />

to display a table, so use them sparingly.<br />

The element supports the following attributes.<br />

Attribute<br />

cellStyle<br />

Description<br />

CSS style to be applied to cells within the target column, for rows in which<br />

this condition evaluates true. For example:<br />

"color: red;"<br />

colName<br />

Required. The name of the column that provides the data value to be<br />

evaluated by the . colName can be a literal string, or it can<br />

contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

<strong>Using</strong> <strong>Zen</strong> 85


<strong>Zen</strong> Tables<br />

Attribute<br />

predicate<br />

rowStyle<br />

Description<br />

The logical operator used to evaluate the condition. predicate may be one<br />

of the following comparison operators: "", "GT", "EQ", "LT", "NEQ",<br />

"GTEQ", "LTEQ", "EXTEQ", "STARTSWITH", or "CONTAINS". The default<br />

predicate is "EQ". For details about each operator, see the next table.<br />

CSS style to apply to rows in which this condition evaluates to true. For<br />

example:<br />

"font-weight: bold;"<br />

targetCol<br />

value<br />

The name of the column that cellStyle applies to. If not specified, colName<br />

is used.<br />

targetCol can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

The literal value to be compared against the value in the column identified<br />

in colName. If enclosed within {} (for example, "{Title}") value is treated<br />

as the name of another column, and the value in that column is used.<br />

value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

When a table is displayed, all elements within the are evaluated individually<br />

for each row in the table. If a evaluates true, then the rowStyle or cellStyle for the condition<br />

is applied to the row or cell, respectively.<br />

The predicate attribute may have the following values.<br />

predicate Values<br />

Predicate<br />

CONTAINS<br />

EQ<br />

EXTEQ<br />

GT<br />

Description<br />

True if the value in the column identified by colName contains (as a<br />

substring) the value specified by value.<br />

True if the value in the column identified by colName is equal to the<br />

value specified by value.<br />

True if the filename in the column identified by colName has the file<br />

extension specified by value.<br />

True if the value in the column identified by colName is greater than<br />

the value specified by value.<br />

86 <strong>Using</strong> <strong>Zen</strong>


Snapshot Mode<br />

Predicate<br />

GTEQ<br />

LT<br />

LTEQ<br />

NEQ<br />

STARTSWITH<br />

Description<br />

True if the value in the column identified by colName is greater than<br />

or equal to the value specified by value.<br />

True if the value in the column identified by colName is less than the<br />

value specified by value.<br />

True if the value in the column identified by colName is less than or<br />

equal to the value specified by value.<br />

True if the value in the column identified by colName is not equal to<br />

the value specified by value.<br />

True if the value in the column identified by colName starts with the<br />

value specified by value.<br />

When you work with %ZEN.Component.tablePane programmatically, you work with <br />

elements as members of the tablePane conditions property, a list collection of %ZEN.Auxiliary.condition<br />

objects. Each in the becomes a member of the conditions collection in<br />

tablePane, associated with its ordinal position: 1, 2, 3, etc.<br />

8.7 Snapshot Mode<br />

A can operate in snapshot mode. In this mode, <strong>Zen</strong> runs the table query once and copies<br />

these results to a temporary location on the server. Subsequent screen refresh operations display data<br />

from this temporary location, rather than resubmitting the query. <strong>Zen</strong> automatically manages the creation<br />

and lifecycle of the temporary snapshot data. Snapshot mode is particularly useful for working with<br />

multipage tables, or with tables that the user can sort.<br />

The element supports the following attributes for snapshot mode.<br />

<strong>Using</strong> <strong>Zen</strong> 87


<strong>Zen</strong> Tables<br />

Attribute<br />

useSnapshot<br />

pageSize<br />

Description<br />

When true, this is in snapshot mode. This means that<br />

whenever data is fetched, it is copied into a server-side temporary<br />

location. Paging and sorting operations use this snapshot data and do<br />

not re-execute the query. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

For snapshot tables, this attribute specifies that you wish to display the<br />

data as multiple pages, and what the page size should be. 0, the default,<br />

means show all data on first page. This can only be set to a non-zero<br />

value when the table is in snapshot mode. Compare maxRows, which<br />

is the total number of rows to fetch in the query.<br />

Any of the query mechanisms described in the previous topics can be used with snapshot or direct<br />

(non-snapshot) mode. The following example specifies an SQL query to be used in snapshot mode:<br />

<br />

The following %ZEN.Component.tablePane properties are not available as XML attributes in the<br />

definition, but they can be useful for working with snapshot tables once the page has been<br />

created.<br />

Attribute<br />

clearSnapshot<br />

currPage<br />

Description<br />

A runtime flag that the client can set to true to force re-execution of<br />

the table query when <strong>Zen</strong> would otherwise use the stored snapshot.<br />

The default is false.<br />

For snapshot tables with multiple pages of data, this is the (1–based)<br />

index number of the currently displayed page of data.<br />

You can also programmatically adjust the values for useSnapshot and pageSize that were originally<br />

set by in XData Contents.<br />

8.7.1 Fetching Data From the Server<br />

The %ZEN.Component.tablePane class offers a getRowData method for tables in snapshot mode only.<br />

getRowData fetches the data values for a given row (0-based) from the server-side snapshot data.<br />

88 <strong>Using</strong> <strong>Zen</strong>


This data is packaged into a JavaScript object whose properties correspond to the names of the columns<br />

in the snapshot table; type conversion is handled appropriately. For non-snapshot tables or out-of-range<br />

row numbers, getRowData returns null.<br />

8.7.2 Navigating Snapshot Tables<br />

Snapshot Mode<br />

Several different options permit users to navigate multipage tables. The and<br />

components provide a basic navigation interface. is particularly<br />

useful for managing multipage tables. For details, see Navigation Buttons.<br />

If you wish to undertake additional programming, the %ZEN.Component.tablePane class provides a<br />

client-side JavaScript API that an application can use to implement the desired paging interface. These<br />

methods work only when the tablePane is in snapshot mode. They include:<br />

Method<br />

getPageCount()<br />

getProperty('currPage')<br />

getProperty('pageSize')<br />

getProperty('rowCount')<br />

Description<br />

Calculates and returns the current number of<br />

pages within the table.<br />

Returns the page number (1–based) of the<br />

current page displayed by the table.<br />

Returns the current page size.<br />

Returns the total number of rows within the<br />

table.<br />

Note that rowCount is a string, and not numeric,<br />

as its value might be "" or "100+". Any<br />

number of rows greater than 100 is represented<br />

as "100+". When testing rowCount<br />

from JavaScript, if you want to convert to a<br />

numeric value use parseInt for base 10:<br />

rowCount = parseInt(rowCount,10);<br />

setProperty('currPage',pageno)<br />

setProperty('pageSize',rows)<br />

Changes the current page displayed by the<br />

table to pageno.<br />

Changes the current page size used by the<br />

table to rows.<br />

<strong>Using</strong> <strong>Zen</strong> 89


<strong>Zen</strong> Tables<br />

8.8 Column Filters<br />

A <strong>Zen</strong> table can create a “filter” to place above the header for any column. A filter is a simple box<br />

with an input field where a user can enter one or more search criteria. When the user submits these<br />

changes, the query associated with the is re-executed using the new criteria. <strong>Zen</strong> updates<br />

the table and nothing else on the page changes.<br />

Filtering works only if the is using an automatically generated SQL statement or an<br />

OnCreateResultSet callback, and the callback generates the appropriate WHERE logic to implement<br />

the data filtering. When your table uses a generated SQL query, your page class can gather what the<br />

user enters; format it appropriately into the %ZEN.Component.tablePane properties groupByClause,<br />

orderByClause, and whereClause; then re-execute the table query.<br />

Important:<br />

If you do not provide a colName value with the element that specifies the<br />

filter, <strong>Zen</strong> does not create the filter.<br />

The element offers the following attributes for filters.<br />

Attribute<br />

filterEnum<br />

Description<br />

If filterType is "enum", filterEnum defines the set of enumerated values<br />

used by the filter as a comma-delimited list. For example:<br />

"red,green,blue"<br />

The enumerated values will be displayed within a combo box. The<br />

names supplied in the filterEnum list will appear as selections in the<br />

combo box unless filterEnumDisplay is defined.<br />

filterEnumDisplay<br />

filterLabel<br />

If filterType is "enum", and if filterEnumDisplay provides a commadelimited<br />

list of values, the combo box displays these values in place<br />

of the corresponding filterEnum values.<br />

The filterEnumDisplay attribute has its ZENLOCALIZE datatype<br />

parameter set to 1 (true). This means it is easy to localize its text into<br />

other languages. See <strong>Zen</strong> Localization.<br />

If specified, this is a label to display for the filter control. If there is a<br />

multipart filter control (such as a filterType of "range"), then<br />

filterLabel is assumed to contain a comma-delimited list of labels.<br />

90 <strong>Using</strong> <strong>Zen</strong>


Column Filters<br />

Attribute<br />

filterOp<br />

filterQuery<br />

filterTitle<br />

filterType<br />

filterValue<br />

Description<br />

If this column has a filter, filterOp is the name of the SQL operator<br />

that should be used in conjunction with the filter. Supported values<br />

are: "", "%STARTSWITH", "=", ">=", "", "


<strong>Zen</strong> Tables<br />

The following sample generates an SQL statement that displays the Name and Department<br />

of employees:<br />

<br />

<br />

<br />

<br />

<br />

This example uses the filterType attribute to specify that the Name column should display<br />

a column filter (“text” indicates that this filter displays a box in which the user may type text). If the<br />

user enters a value in the box (such as “A”) and presses Enter, the table will be updated to only show<br />

rows where the Name column starts with “A”. (If the does not specify a filterOp value, the<br />

default matching operation is %STARTSWITH.)<br />

For the Department column the example displays a more sophisticated filter: a combo box showing 3<br />

possible values. To do this, it sets the filterType to “enum” and sets filterEnum to a commadelimited<br />

list of possible values. It also specifies that an exact match is required, by setting the filterOp<br />

value to "=".<br />

A has filters active and enabled by default. You do not need to supply any <br />

attributes to enable filtering. However, should you want to override the default settings, <br />

offers the following attributes that control filtering for the table as a whole, not just for individual<br />

columns.<br />

Attribute<br />

autoExecute<br />

filtersDisabled<br />

Description<br />

If true, this attribute causes the table query to be executed whenever<br />

a filter value is changed. autoExecute is "true" by default. When false,<br />

a page must explicitly cause the to run its query by<br />

calling its executeQuery method.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

If true, disable column filters (if any). When true, column filters are<br />

still displayed, but they are inactive. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

92 <strong>Using</strong> <strong>Zen</strong>


Column Links<br />

Attribute<br />

headerLayout<br />

Description<br />

Controls how to display the table header when column filters are used.<br />

Possible values are:<br />

• "filtersOnTop" — Display column filters above column headers.<br />

This is the default.<br />

• "headersOnTop" — Display column headers above column filters.<br />

showFilters<br />

If true, display column filters (if any) above the column headers. If<br />

false, do not display filters. The default is true.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

8.9 Column Links<br />

Columns within a <strong>Zen</strong> table can display links, such as a link that takes the user to another page to edit<br />

the details of the object displayed within the current row. This link can either be displayed within a<br />

column that contains a data value (in this case, the data value is displayed as a link), or as an extra<br />

column in the table that contains the link.<br />

The element offers the following attributes for links.<br />

Attribute<br />

link<br />

Description<br />

If specified, this column is displayed as a link using the value of the link<br />

property as a URI. If you want to invoke a client-side JavaScript method<br />

in the link, start the URI with javascript: as in:<br />

link="javascript:zenPage.myMethod();"<br />

linkCaption<br />

If this column has a link defined and does not display a data value, the<br />

linkCaption specifies the text to use as the caption for the link.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

<strong>Using</strong> <strong>Zen</strong> 93


<strong>Zen</strong> Tables<br />

Attribute<br />

linkConfirm<br />

Description<br />

If specified and this column has a link defined, the linkConfirm text is<br />

displayed as a confirmation message before the link is executed.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

For example:<br />

<br />

<br />

<br />

<br />

<br />

This example does the following:<br />

1. The sql value specifies that this table will display information about the top 100 items<br />

in the MyApp.Inventory table ordered by price.<br />

2. The needs the value of the “ID” column (as part of the links) but there is no need to<br />

display this value. Therefore, the hidden value is true.<br />

3. The needs the “Item” column to contain a link to a page that displays information<br />

about a specific item. Therefore, the link value defines this link. The linkTitle<br />

value defines a tooltip message that will be displayed when the user moves the mouse over this<br />

link.<br />

4. The defines an extra column (with no data displayed within it) that contains an “Add<br />

to cart” link. This link invokes a client-side addToCart method when the user clicks on it. Specifying<br />

a value for the linkConfirm value indicates that the user will have a chance to<br />

confirm this choice before the link is executed.<br />

The two links used within this example make use of the <strong>Zen</strong> expression syntax to include the value of<br />

row-specific data within the link. See <strong>Zen</strong> Runtime Expressions. The following expression refers to<br />

the ID column within the current row of the table: #(%query.ID)#<br />

94 <strong>Using</strong> <strong>Zen</strong>


User Interactions<br />

8.10 User Interactions<br />

<strong>Zen</strong> tables provide built-in mechanisms to support basic user interactions such as navigating pages,<br />

sorting columns, and selecting rows in a table.<br />

8.10.1 Navigation Buttons<br />

The component automatically displays a set of buttons for moving through the pages<br />

of a . The has identical syntax, but displays extra buttons to help<br />

users navigate large, multipage tables.<br />

To use either component, place it anywhere on the same page as a and set its tablePaneId<br />

attribute value to match the id value from the . For example:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

8.10.2 Navigation Keys<br />

The can specify event handling for user key clicks as follows.<br />

Property<br />

onkeypress<br />

Description<br />

If useKeys is true, this client-side JavaScript expression runs<br />

whenever the user presses a key (Up, Down, Page Up, Page Down,<br />

Home, End) while focus is in the table.<br />

When providing a value for this attribute, use double quotes to<br />

enclose the value and single quotes (if needed) within the<br />

JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

<strong>Using</strong> <strong>Zen</strong> 95


<strong>Zen</strong> Tables<br />

Property<br />

useKeys<br />

Description<br />

If true, this tablePane captures user keystrokes (Up, Down, Page<br />

Up, Page Down, Home, End) and uses them for simple table navigation.<br />

The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

8.10.3 Sorting Tables<br />

The user can click on a column header and cause this action to sort the table according to the data in<br />

that column: First click, ascending order; second click, descending order; and so on. You can set an<br />

initial value for sortOrder when you add the to the page, but generally it takes its values<br />

at runtime, due to user interactions.<br />

Property<br />

sortOrder<br />

Description<br />

When the user clicks on a column header, <strong>Zen</strong> re-executes the table query<br />

(unless the table is in snapshot mode) and sorts the table based on the<br />

values in that column and the order specified by the sortOrder value.<br />

sortOrder toggles between its possible values "asc" (sort in ascending<br />

order) and "desc" (sort in descending order) as the user repeats clicks in<br />

that column header.<br />

sortOrder does not affect the query itself (it does not interact with the query<br />

ORDER BY setting). sortOrder simply controls the order in which the table<br />

displays the resultset returned by the query.<br />

The sortOrder value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

8.10.4 Selecting Rows and Columns<br />

The user can select rows or columns within a <strong>Zen</strong> table by clicking on them. <strong>Zen</strong> indicates the current<br />

row visually and notifies the application of the event by triggering the event handler provided by the<br />

onselectrow attribute.<br />

%ZEN.Component.tablePane supports a number of properties for row and column selection. Many of<br />

these properties can be set as attributes, but some of them can only take their values at<br />

runtime in response to user actions.<br />

96 <strong>Using</strong> <strong>Zen</strong>


User Interactions<br />

Property<br />

currColumn<br />

multiSelect<br />

ondblclick<br />

Description<br />

The colName of the column most recently selected by the user.<br />

You may allow user actions to provide a value for this property, or<br />

you can set it. The currColumn value can be a literal string, or it<br />

can contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

If true, the user can select multiple rows within the table. <strong>Zen</strong><br />

displays an extra column, containing check boxes, to indicate which<br />

rows are selected. The default is false. multiSelect and rowSelect<br />

can be true or false independently of each other.<br />

Client-side JavaScript expression that runs whenever the user<br />

double-clicks on a row within this table. Generally this expression<br />

invokes a client-side JavaScript method defined in the page class.<br />

This method becomes the “ondblclick event handler” for the<br />

.<br />

When providing a value for an event handler attribute such as<br />

ondblclick, use double quotes to enclose the value and single quotes<br />

(if needed) within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

onheaderClick<br />

onselectrow<br />

onmultiselect<br />

rowSelect<br />

selectedIndex<br />

Client-side JavaScript expression that runs whenever the user clicks<br />

on a column header within this table. <strong>Zen</strong> stores the name of this<br />

column in the currColumn property.<br />

If rowSelect is true, this is the client-side JavaScript expression that<br />

runs whenever the user selects a new row within this table. This<br />

will only happen if showRowSelector is true.<br />

If multiSelect is true, this is the client-side JavaScript expression<br />

that runs whenever the user changes the set of multiply-selected<br />

rows within this table.<br />

If true, the user can select a row within the table (one row at a time).<br />

The default is true. multiSelect and rowSelect can be true or false<br />

independently of each other.<br />

The (0–based) index number of the currently selected row. This<br />

value is relevant only if the showRowSelector property is true. For<br />

snapshot tables, this is row number within the current page.<br />

<strong>Using</strong> <strong>Zen</strong> 97


<strong>Zen</strong> Tables<br />

Property<br />

selectedRows<br />

showRowSelector<br />

value<br />

Description<br />

Read-only. For tables in which multiSelect is true, this string<br />

indicates which rows are currently selected.The string is in the form<br />

"1,,,1,,,1" with "1" indicating a selected row.<br />

If true, and if row(s) are selected, the table displays an extra column<br />

that indicates the selected row(s). The default is true.<br />

Read-only. This is the logical value used to determine which is the<br />

currently selected row. value works with valueColumn. The value<br />

may be empty ("").<br />

Do not access this value directly; use getProperty('value')<br />

instead.<br />

valueColumn<br />

A can have a logical value defined. Each time the<br />

table is refreshed, in each row <strong>Zen</strong> tests this logical value against<br />

the actual value that appears in the valueColumn in that row. <strong>Zen</strong><br />

selects any row(s) that contain value in valueColumn. This implies<br />

the following:<br />

• You can preset the value of a and the row(s) that<br />

match will be selected when the table is first displayed.<br />

• The current selection is preserved when you sort the rows in a<br />

table.<br />

8.11 Table Refresh<br />

When you refresh a table, only the table refreshes. It is not necessary for the entire <strong>Zen</strong> page to refresh<br />

itself in order to refresh a table.<br />

Typically, <strong>Zen</strong> refreshes the visible contents of the table automatically as needed. When you work<br />

with tables programmatically, you can also explicitly refresh table contents. The techniques are as<br />

follows:<br />

• Set the refreshRequired property of the %ZEN.Component.tablePane to true (1) from a server-side<br />

method. This forces the tablePane to re-execute its query.<br />

• Call the executeQuery method of the %ZEN.Component.tablePane. This causes the data query<br />

to be re-executed and updates the visible contents of the table to reflect the current values of<br />

tablePane properties.<br />

98 <strong>Using</strong> <strong>Zen</strong>


Table Touchups<br />

8.12 Table Touchups<br />

Any time you set an attribute value for in XData Contents, the corresponding property<br />

in the tablePane object automatically acquires this value. This might be just enough programming for<br />

your purposes. Nevetheless, %ZEN.Component.tablePane offers many more opportunities for programmatic<br />

interaction on the client or server sides, for example:<br />

• Touching up values set in XData Contents, just prior to display, by setting tablePane properties<br />

in the %OnAfterCreatePage callback of the page class.<br />

• Examining read-only properties of %ZEN.Component.tablePane such as lastUpdate and rowCount<br />

to determine the current state of the table. Note that rowCount is a string, and not numeric, as its<br />

value might be "" or "100+". Any number of rows greater than 100 is represented as "100+".<br />

• Resetting values of certain tablePane properties and then refreshing the table.<br />

<strong>Using</strong> <strong>Zen</strong> 99


9<br />

<strong>Zen</strong> and SVG<br />

Scalable Vector Graphics (SVG) is a language that allows you to describe two-dimensional vector<br />

graphics in XML format. The SVG language specification is available on the Web site<br />

www.w3.org/TR/SVG/.<br />

<strong>Zen</strong> uses SVG to display high-performance, data-driven charts and meters. You can use the built-in<br />

SVG components to define eye-catching corporate dashboards that update their statistics in real time.<br />

You can also define your own SVG components. An SVG component is any component that inherits<br />

from %ZEN.SVGComponent.svgComponent. These components render dynamic SVG images that<br />

change their appearance in response to data values.<br />

Note:<br />

If you want to display a static SVG file on the <strong>Zen</strong> page, use . If you want to use a<br />

static SVG file as the image for a button control, use . The conventions described<br />

in the following topics apply to dynamic SVG components only.<br />

This chapter describes how to place SVG components on the <strong>Zen</strong> page. Topics include:<br />

• Layout<br />

• Style<br />

• Meters<br />

• Charts<br />

• The radial navigator component<br />

• Drawing your own SVG<br />

<strong>Using</strong> <strong>Zen</strong> 101


<strong>Zen</strong> and SVG<br />

9.1 SVG Component Layout<br />

The following components allow you to place SVG components on a <strong>Zen</strong> page:<br />

• <br />

• <br />

• <br />

9.1.1 <br />

is a <strong>Zen</strong> component that creates a rectangular frame on the <strong>Zen</strong> page, into which you can<br />

place SVG components. Only SVG components may appear inside this frame. Any dynamic SVG<br />

component, such as a meter or chart, requires an to contain it.<br />

inherits from %ZEN.Component.component. This gives the usual component<br />

style attributes: height, width, label, etc. See <strong>Zen</strong> Style. This also allows to be placed<br />

within a (or contained within an or ) just like any other <strong>Zen</strong> component.<br />

See <strong>Zen</strong> Layout.<br />

The following figure shows a mix of <strong>Zen</strong> components and SVG components on a page. This is similar<br />

to the output provided by the sample class ZENDemo.Dashboard in the SAMPLES namespace.<br />

102 <strong>Using</strong> <strong>Zen</strong>


SVG Component Layout<br />

The following XData Contents block contains the components that produced the above figure. These<br />

are a mix of:<br />

• <strong>Zen</strong> components (,,, , , )<br />

• SVG components (, , , , ,<br />

)<br />

<strong>Using</strong> <strong>Zen</strong> 103


<strong>Zen</strong> and SVG<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

This is an example of a <strong>Zen</strong> Dashboard:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

An element may contain as many nested and elements as are<br />

required to achieve the desired layout. has the following attributes.<br />

104 <strong>Using</strong> <strong>Zen</strong>


SVG Component Layout<br />

Attribute<br />

<strong>Zen</strong> component<br />

attributes<br />

backgroundStyle<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong><br />

component. The previous chapter, <strong>Zen</strong> Style, describes them.<br />

SVG CSS style definition (Styles within SVG are CSS compliant, but<br />

there is a different set of styles available.) Specifies the background<br />

style for the frame.This style must include a fill value, or mouse events<br />

within this frame will not work correctly. The default backgroundStyle<br />

is:<br />

"fill: white;"<br />

disabled<br />

dragCanvas<br />

editMode<br />

If true, this frame and its children are disabled. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

If true, the user can use the pointing device (mouse) to drag the canvas<br />

of this frame. This updates he values of the offsetX and offsetY<br />

attributes and moves the shapes on the canvas. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Edit mode for this frame. Possible values are:<br />

• "none" — The user cannot edit the contents of this frame. This is<br />

the default.<br />

• "select" — The user can click on an SVG component to select it.<br />

• "drag" — The user can click on an SVG component, hold down<br />

the mouse button, and drag the SVG component to a new position.<br />

frameStyle<br />

CSS style definition that applies to this frame. For example, to produce<br />

the recessed, beveled border shown in the illustration above, you<br />

would use:<br />

frameStyle="border-style: inset;"<br />

gridX<br />

If snapToGrid is true, gridX defines the HTML width of each cell in the<br />

sizing grid. The default is 25.<br />

<strong>Using</strong> <strong>Zen</strong> 105


<strong>Zen</strong> and SVG<br />

Attribute<br />

gridY<br />

layout<br />

offsetX<br />

offsetY<br />

ondragCanvas<br />

Description<br />

If snapToGrid is true, gridY defines the HTML height of each cell in<br />

the sizing grid. The default is 25.<br />

Specifies how the SVG components within this frame should be laid<br />

out. Possible values are "horizontal" and "vertical".<br />

If layout is set to "none" or the empty value "", components may be<br />

placed using specific coordinates x and y. See the x and y attributes<br />

in the topic SVG Component Style.<br />

Offset, along the x-axis, of the coordinates of this frame from its upper,<br />

left-hand corner. The default is 0.<br />

Offset, along the y-axis, of the coordinates of this frame from its upper,<br />

left-hand corner. The default is 0.<br />

Client-side JavaScript expression that runs each time the user drags<br />

the background canvas using a pointing device. Generally this<br />

expression invokes a client-side JavaScript method defined in the<br />

page class. A boolean variable, done, is passed to this event handler<br />

to indicate if the operation is complete.<br />

As with all event handler expressions including onmouseWheel,<br />

onmoveItem, etc:<br />

• When providing a value for this attribute, use double quotes to<br />

enclose the value and single quotes (if needed) within the<br />

JavaScript expression. For example:<br />

<br />

• The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

onmouseWheel<br />

onmoveItem<br />

Client-side JavaScript expression that runs whenever the user moves<br />

the mouse wheel over the background rectangle of this frame. Currently<br />

only available in FireFox.<br />

Client-side JavaScript expression that runs whenever this frame is in<br />

drag mode and the user moves one or more selected items. Refer to<br />

the selectedItems property for the list of items. A boolean variable,<br />

done, is passed to this event handler to indicate if the operation is<br />

complete.<br />

106 <strong>Using</strong> <strong>Zen</strong>


SVG Component Layout<br />

Attribute<br />

onresizeItem<br />

onselectItem<br />

onzoom<br />

snapToGrid<br />

svgAutoSize<br />

svgHeight<br />

Description<br />

Client-side JavaScript expression that runs whenever this frame is in<br />

drag mode and the user resizes one or more selected items. Refer to<br />

the selectedItems property for the list of items. A boolean variable,<br />

done, is passed to this event handler to indicate if the operation is<br />

complete.<br />

Client-side JavaScript expression that runs whenever the user changes<br />

the number of selected items in this frame (by selecting or unselecting<br />

an item). A variable, item, is passed to this event handler and refers<br />

to the item most recently selected or unselected.<br />

Client-side JavaScript expression that runs whenever the user changes<br />

the zoom level for this frame.<br />

If true, all mouse operations (sizing and dragging) are constrained to<br />

occur on the grid defined by gridX and gridY. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Controls the size of the SVG drawing canvas within the frame. If<br />

dragCanvas is true, the svgAutoSize property is ignored. Otherwise,<br />

if svgAutoSize is true, <strong>Zen</strong> calculates (and updates) the canvas size<br />

automatically based on the frame contents, with the minimum canvas<br />

size being svgWidth by svgHeight. If svgAutoSize is false, the canvas<br />

size is determined by the values of svgWidth and svgHeight.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Controls the size of the SVG drawing canvas within the frame.<br />

svgHeight gives the canvas height (using any valid SVG measurement<br />

units). If not specified, the default svgHeight is 100% of the height of<br />

the . If height is also not specified, the default height (and<br />

svgHeight) is 100.<br />

<strong>Using</strong> <strong>Zen</strong> 107


<strong>Zen</strong> and SVG<br />

Attribute<br />

svgPage<br />

Description<br />

(Optional) Identifies a specialized CSP page that serves SVG content,<br />

defining styles and colors for SVG components in the frame. If provided,<br />

the svgPage value must be the name of a class that extends<br />

%ZEN.SVGComponent.svgPage. Otherwise, the frame uses the base<br />

class %ZEN.SVGComponent.svgPage by default.<br />

When you provide a value for the svgPage attribute, you can also<br />

include elements within the . <strong>Zen</strong> passes<br />

the value strings from these elements to the svgPage<br />

class as URI parameters. For example:<br />

<br />

The value supplied for a can be a literal string, or it can<br />

contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

svgWidth<br />

zoom<br />

zoomLevels<br />

Controls the size of the SVG drawing canvas within the frame.<br />

svgWidth gives the canvas width (using any valid SVG measurement<br />

units). If not specified, the default svgWidth is 100% of the width of<br />

the . If width is also not specified, the default width (and<br />

svgWidth) is 300.<br />

Decimal value, at least 1.0 (the decimal portion of the number may<br />

be omitted). This value indicates the zoom factor for the frame. 100<br />

means no zoom; this is the default. Values larger than 100 increase<br />

image size, while smaller values decrease it.<br />

Comma-separated list of suggested zoom values. The default is:<br />

"10,25,50,75,100,125,150,175,200,300,400,500"<br />

zoomWithWheel<br />

If true, this frame automatically zooms in and out in response to mouse<br />

wheel events. The default is false. Currently only available in FireFox.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Important:<br />

It is not possible for to contain any component that inherits from<br />

%ZEN.Component.component, such as , , , ,<br />

, , , or any of the other <strong>Zen</strong> components discussed in this<br />

book. can contain SVG components only.<br />

108 <strong>Using</strong> <strong>Zen</strong>


SVG Component Layout<br />

9.1.2 <br />

is a special container designed to contain and lay out SVG components within .<br />

is not a <strong>Zen</strong> component (%ZEN.Component.component), nor is it a <strong>Zen</strong> group component<br />

(%ZEN.Component.group). is an <strong>Zen</strong> SVG component<br />

(%ZEN.SVGComponent.svgComponent) with the ability to contain other <strong>Zen</strong> SVG components.<br />

has the following attributes.<br />

Attribute<br />

SVG<br />

component<br />

attributes<br />

disabled<br />

layout<br />

Description<br />

has the same general-purpose attributes as any SVG<br />

component.<br />

If true, this group and its children are disabled (hidden).The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

Specifies how the SVG components within this group should be laid out.<br />

Possible values are "horizontal" and "vertical".<br />

If layout is set to "none" or the empty value "", components may be placed<br />

using specific coordinates x and y. See the x and y attributes in the topic<br />

SVG Component Style.<br />

9.1.3 <br />

The element is useful within containers. Use with a width value<br />

to inject additional space in a horizontal , or height for additional space within a vertical<br />

. supports all of the SVG component attributes.<br />

9.1.4 <br />

The <strong>Zen</strong> element draws a simple rectangle. This is not the same as the element defined<br />

by the SVG language specification. <strong>Zen</strong> is a built-in <strong>Zen</strong> SVG component that you can place<br />

within an or .<br />

The <strong>Zen</strong> element takes up space within an or , but in a different way<br />

than . The conceptual difference between and is that may<br />

have visible style attributes, such as a fill color.<br />

<strong>Using</strong> <strong>Zen</strong> 109


<strong>Zen</strong> and SVG<br />

Attribute<br />

SVG<br />

component<br />

attributes<br />

rx<br />

style<br />

Description<br />

has the same general-purpose attributes as any SVG component.<br />

Radius of curve for the corners (using any valid SVG measurement units).<br />

SVG CSS style definition. (Styles within SVG are CSS compliant, but there<br />

is a different set of styles available.)<br />

9.2 SVG Component Attributes<br />

All SVG components have the following style attributes. These are entirely distinct from the attributes<br />

supported by ordinary <strong>Zen</strong> components.<br />

SVG Component Attributes<br />

Attribute<br />

height<br />

hidden<br />

onclick<br />

Description<br />

Height of this component (using any valid SVG measurement<br />

units). The exact effect of setting this value depends on the<br />

component. In the case of built-in SVG components, the effect is<br />

usually straightforward. A height value larger than the height of<br />

the containing will cause the SVG component to<br />

appear cropped by the frame.<br />

If true, this component is disabled (hidden). The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

Client-side JavaScript expression that runs each time the user<br />

clicks the mouse on this shape. Generally this expression invokes<br />

a client-side JavaScript method defined in the page class.<br />

When providing a value for this attribute, use double quotes to<br />

enclose the value and single quotes (if needed) within the<br />

JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

110 <strong>Using</strong> <strong>Zen</strong>


SVG Component Attributes<br />

Attribute<br />

name<br />

id<br />

preserveAspectRatio<br />

viewBoxHeight<br />

viewBoxWidth<br />

width<br />

x<br />

y<br />

Description<br />

Specifies a name for the component.<br />

Name that can be used to select the SVG component so that its<br />

attributes can be updated. For example, displays that use meters<br />

might periodically update the value that the meter represents.<br />

By default, <strong>Zen</strong> preserves the aspect ratio (height relative to width)<br />

for any SVG component when you change its size. If you set<br />

preserveAspectRatio to "none", <strong>Zen</strong> does not preserve the aspect<br />

ratio and allows your height and width changes to operate<br />

independently of each other.<br />

Height of the view box for this component (using any valid SVG<br />

measurement units). If a viewBoxHeight attribute is provided, its<br />

value is used as the height of the view box. Otherwise, the height<br />

value for the component is used.<br />

Width of the view box for this component (using any valid SVG<br />

measurement units). If a viewBoxWidth attribute is provided, its<br />

value is used as the width of the view box. Otherwise, the width<br />

value for the component is used.<br />

Width of this component (using any valid SVG measurement units).<br />

The exact effect of setting this value depends on the component.<br />

In the case of built-in SVG components, the effect is usually<br />

straightforward. A width value larger than the width of the containing<br />

will cause the SVG component to appear cropped<br />

by the frame.<br />

x position of this component (using any valid SVG measurement<br />

units). The actual position of the component may depend on the<br />

layout of its enclosing . If the has vertical<br />

or horizontal layout, this x coordinate is ignored. However, if<br />

layout="" this x coordinate takes effect. x is a positive value<br />

relative to an origin of (0,0) at the top left corner of the .<br />

y position of this component.<br />

<strong>Using</strong> <strong>Zen</strong> 111


<strong>Zen</strong> and SVG<br />

9.3 Meters<br />

A meter is an SVG component that displays a graphical representation of a single numeric value. Each<br />

meter is a class derived from %ZEN.SVGComponent.meter that generates the SVG required to display<br />

itself.<br />

<strong>Zen</strong> provides several built-in meters. To place one of them on the <strong>Zen</strong> page, provide the corresponding<br />

meter element within an or :<br />

• <br />

• <br />

• <br />

• <br />

• <br />

• <br />

• To create your own style of meter, see Custom Components<br />

This topic describes how to supply a meter with a value, lists the attributes that all meters share in<br />

common, then describes the unique attributes for each type of meter listed above.<br />

9.3.1 Providing Data for Meters<br />

Your code can dynamically update the value displayed by a meter in one of two ways:<br />

• From a JavaScript method in the page class, set the meter’s value attribute using the meter class<br />

methods getComponentById and setValue as follows:<br />

this.getComponentById("myMeterID").setValue(myNewValue);<br />

Where myMeterID matches the id attribute value for the meter, and myNewValue is a variable that<br />

contains a single, numeric value.<br />

• Associate the meter with a data controller, as described in the chapter Model View Controller.<br />

For example, if your XData Contents block contains an reference that looks like<br />

this:<br />

<br />

And if the referenced modelClass myPackage.MyModel contains a property called Automobiles,<br />

then your XData Contents block can also contain a meter definition that looks like this:<br />

112 <strong>Using</strong> <strong>Zen</strong>


Meters<br />

<br />

This technique works when the meter’s controllerId value matches the id value,<br />

and the meter’s dataBinding value matches the name of a property defined in the <br />

modelClass.<br />

9.3.2 Meter Attributes<br />

All meters have the following attributes, which define their style and behavior.<br />

Meter Component Attributes<br />

Attribute<br />

SVG<br />

component<br />

attributes<br />

animate<br />

controllerId<br />

dataBinding<br />

label<br />

Description<br />

All meters have the same general-purpose attributes as any SVG<br />

component.<br />

Some of the built-in <strong>Zen</strong> meters provide animation. For example, if the<br />

meter uses a needle to indicate a value, animation causes the needle<br />

to “swing” from the previous value to the new value. If a meter supported<br />

animation, this attribute controls whether animation is on (true)<br />

or off (false). The default is "true".<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Identifies the data controller that provides the data for this meter. The<br />

controllerId value must match the id value provided for that<br />

component. See Model View Controller.<br />

If this meter is associated with a data controller, this attribute identifies<br />

the specific property within the modelClass that<br />

provides the value for this control. See Model View Controller.<br />

A text label for the meter.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

<strong>Using</strong> <strong>Zen</strong> 113


<strong>Zen</strong> and SVG<br />

Attribute<br />

labelStyle<br />

onnotifyView<br />

Description<br />

SVG CSS style definition. (Styles within SVG are CSS compliant, but<br />

there is a different set of styles available.) When <strong>Zen</strong> lays out this<br />

meter, it applies this style to the label text.<br />

This attribute applies if the meter is associated with a data controller.<br />

The onnotifyView value is a client-side JavaScript expression that is<br />

executed each time the data controller connected to this meter raises<br />

an event. Generally this expression invokes a client-side JavaScript<br />

method defined in the page class. This method becomes the<br />

“onnotifyView event handler” for the meter. See Model View Controller.<br />

When providing a value for this attribute, use double quotes to enclose<br />

the value and single quotes (if needed) within the JavaScript expression.<br />

For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

rangeLower<br />

rangeUpper<br />

scaleFactor<br />

thresholdLower<br />

thresholdUpper<br />

Integer or decimal value that defines the low end of the range for this<br />

meter. The default is 0.<br />

Integer or decimal value that defines the high end of the range for this<br />

meter. The default is 100.<br />

Integer or decimal factor used to scale the values provided to this<br />

meter. <strong>Zen</strong> scales the incoming values before comparing them with<br />

rangeLower, rangeUpper, and so on. The default is 1 (no scaling).<br />

Integer or decimal value that defines a threshold for meter behavior.<br />

The meter will do something when the meter value falls below this<br />

value. Typically, the thresholdLower value is greater than rangeLower<br />

and serves as a warning that the meter value is approaching<br />

rangeLower. The default is 0.<br />

Integer or decimal value that defines a threshold for meter behavior.<br />

The meter will do something when the meter value rises above this<br />

value. Typically, the thresholdUpper value is less than rangeUpper<br />

and serves as a warning that the meter value is approaching<br />

rangeUpper. The default is 90.<br />

114 <strong>Using</strong> <strong>Zen</strong>


Meters<br />

Attribute<br />

value<br />

Description<br />

The current integer or decimal value of the meter (actually stored as<br />

a string). Although you can set this value while placing the meter on<br />

the page, generally you do not do this. Instead, you use<br />

getComponentById and setValue, or associate the meter with a<br />

%ZEN.Auxiliary.dataController, as described in the paragraph prior to this<br />

table.<br />

9.3.3 <br />

The fuel gauge is a narrow, vertical gauge with a needle that moves from left to right to indicate a<br />

value within a specific range. The gauge distributes marks or “ticks” proportionally across its range.<br />

The meter attributes rangeLower and rangeUpper define the range, with the rangeLower value at left<br />

and the rangeUpper value at right.<br />

The fuel gauge displays its current value in a text box at the center of the gauge.<br />

You may specify warning lights to appear at the upper left or right of the gauge, above the ticks. These<br />

lights change color as the needle approaches them. The light at right changes color when the meter<br />

value rises to or above thresholdUpper. The light at left changes color when the meter value falls to<br />

or below thresholdLower.<br />

There is always a thresholdLower warning light with a default setting of 0. You must specify a<br />

thresholdUpper value if you want a warning light to appear at the top of the range as well.<br />

<strong>Using</strong> <strong>Zen</strong> 115


<strong>Zen</strong> and SVG<br />

Attribute<br />

Meter attributes<br />

highLampColor<br />

Description<br />

has the same general-purpose attributes as any meter.<br />

String containing a CSS color value. This is the color that the displays when its value exceeds thresholdUpper. The default<br />

is a pre-defined <strong>Zen</strong> color that produces a “glowing” effect through<br />

shading:<br />

url(#glow-red)<br />

Several glow colors are defined in the class<br />

%ZEN.SVGComponent.svgPage. always references this<br />

class, or some subclass of it, through its svgPage attribute, so these<br />

colors are always available to any SVG component in the frame.<br />

logo<br />

lowLampColor<br />

Text label for the face of the meter (similar to "<strong>Zen</strong>" in the illustration<br />

above).<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

String containing a CSS color value. This is the color that the displays when its value exceeds thresholdUpper. The default<br />

is a pre-defined <strong>Zen</strong> color:<br />

url(#glow-red)<br />

9.3.4 <br />

The indicator lamp is a rectangular bar that changes its fill pattern depending on the meter value.<br />

Essentially there are three possible states: above thresholdUpper, below thresholdLower, or between<br />

the two values.<br />

If the meter has a label attribute, this text appears in the middle of the indicator lamp with the style<br />

defined by labelStyle.<br />

116 <strong>Using</strong> <strong>Zen</strong>


Meters<br />

Attribute<br />

Meter<br />

attributes<br />

highStyle<br />

Description<br />

has the same general-purpose attributes as any meter,<br />

plus the attributes described in this table.<br />

SVG CSS style definition. Specifies the fill style for the <br />

when its value exceeds thresholdUpper. The highStyle must include a fill<br />

value, or mouse events within the shape will not work correctly.The default<br />

highStyle uses a pre-defined <strong>Zen</strong> color that produces a “glowing” effect<br />

through shading:<br />

"fill: url(#glow-green);"<br />

Several glow colors are defined in the class %ZEN.SVGComponent.svgPage.<br />

always references this class, or some subclass of it, through<br />

its svgPage attribute, so these colors are always available to any SVG<br />

component in the frame.<br />

lowStyle<br />

SVG CSS style definition. Specifies the fill style for the <br />

when its value falls below thresholdLower. The lowStyle must include a<br />

fill value, or mouse events within the shape will not work correctly. The<br />

default lowStyle uses a pre-defined <strong>Zen</strong> color:<br />

"fill: url(#glow-red);"<br />

normalStyle<br />

SVG CSS style definition. Specifies the fill style for the <br />

when its value is between thresholdLower and thresholdUpper. The<br />

normalStyle must include a fill value, or mouse events within the shape<br />

will not work correctly. The default normalStyle uses a pre-defined <strong>Zen</strong><br />

color:<br />

"fill: url(#glow-blue);"<br />

9.3.5 <br />

<strong>Using</strong> <strong>Zen</strong> 117


<strong>Zen</strong> and SVG<br />

The light bar provides a stack of lamps arranged in a vertical bar. The light bar is similar to the traffic<br />

light, but its larger number of lamps provide a sense of movement from one end of the scale to the<br />

other.<br />

The light bar is intended to appear “off” when the value is low, and fully lit when the value is high.<br />

The color of the bar shades from green (at the bottom of the scale) to yellow and red (at the top of the<br />

scale), implying that you should stop and address a problem when the value is high.<br />

Sometimes a low number indicates a condition that requires attention. If this is the case you can reverse<br />

the sense of a light bar by inverting the values for rangeLower and rangeUpper. Then the fully lit lamp<br />

indicates low values, and the “off” lamp indicates high values.<br />

Warning lights appear at the top or bottom left of the light bar. The top light changes color when the<br />

meter value rises to or above thresholdUpper. The bottom light changes color when the meter value<br />

falls to or below thresholdLower. You can specify what color you want to use for these lights. You<br />

cannot change the colors for the light bar itself (green, yellow, red).<br />

Note:<br />

When you reverse rangeLower and rangeUpper, do not at the same time reverse<br />

thresholdUpper and thresholdLower.<br />

Attribute<br />

Meter attributes<br />

highLampColor<br />

Description<br />

has the same general-purpose attributes as any meter, plus<br />

the attributes described in this table.<br />

String containing a CSS color value.This is the color that the <br />

displays when its value exceeds thresholdUpper. The default is a predefined<br />

<strong>Zen</strong> color that produces a “glowing” effect through shading:<br />

url(#glow-red)<br />

Several glow colors are defined in the class<br />

%ZEN.SVGComponent.svgPage. always references this<br />

class, or some subclass of it, through its svgPage attribute, so these<br />

colors are always available to any SVG component in the frame.<br />

lowLampColor<br />

String containing a CSS color value.This is the color that the <br />

displays when its value falls below thresholdLower. The default is a<br />

pre-defined <strong>Zen</strong> color: url(#glow-red)<br />

118 <strong>Using</strong> <strong>Zen</strong>


Meters<br />

9.3.6 <br />

The smiley is the familiar yellow circle with two eyes and a smile. The mouth line changes depending<br />

on the meter value. The mouth forms a smile when the meter value is near rangeUpper. The mouth is<br />

a horizontal line at the midpoint between rangeLower and rangeUpper. The mouth forms a frown<br />

when the meter value is near rangeLower. This is useful when a large number indicates a positive<br />

condition, and a small number indicates a negative condition.<br />

You can reverse the sense of a smiley by inverting the values for rangeLower and rangeUpper. Then<br />

the smile occurs at low values, and the frown at high values.<br />

has no unique attributes. It has the usual meter attributes. It ignores any threshold values.<br />

9.3.7 <br />

The speedometer is a circular gauge with a needle that moves from lower left, all the way around to<br />

lower right, to indicate a value within a specific range. The gauge distributes marks or “ticks” proportionally<br />

across its range. The meter attributes rangeLower and rangeUpper define the range, with the<br />

rangeLower value at left and the rangeUpper value at right.<br />

By default, the speedometer displays its current value in a text box at the center of the gauge. However,<br />

you can specify that this text box actually contains a different value that you control separately. Use<br />

the independentOdometer and odometerValue attributes for this.<br />

You may specify warning lights to appear at the lower left or lower right of the gauge. These lights<br />

change color as the needle approaches them. The light at right changes color when the meter value<br />

<strong>Using</strong> <strong>Zen</strong> 119


<strong>Zen</strong> and SVG<br />

rises to or above thresholdUpper. The light at left changes color when the meter value falls to or below<br />

thresholdLower.<br />

Attribute<br />

Meter attributes<br />

highLampColor<br />

Description<br />

has the same general-purpose attributes as<br />

any meter, plus the attributes described in this table.<br />

String containing a CSS color value. This is the color that the<br />

displays when its value exceeds<br />

thresholdUpper. The default is a pre-defined <strong>Zen</strong> color that<br />

produces a “glowing” effect through shading:<br />

url(#glow-red)<br />

Several glow colors are defined in the class<br />

%ZEN.SVGComponent.svgPage. always references<br />

this class, or some subclass of it, through its svgPage attribute,<br />

so these colors are always available to any SVG component in<br />

the frame.<br />

independentOdometer<br />

logo<br />

lowLampColor<br />

odometerValue<br />

If true, this meter can display an additional value independent<br />

of its needle value, in a text box at the center of the gauge. If<br />

false, the value in the text box is the same as the needle value.<br />

The default is false.<br />

This attribute has the underlying data type<br />

%ZEN.Datatype.boolean. It has the value "true" or "false" in XData<br />

Contents, 1 or 0 in server-side code, true or false in client-side<br />

code. See Datatype Classes.<br />

Text label for the face of the meter (similar to "<strong>Zen</strong>" in the illustration<br />

above).<br />

Although you enter ordinary text for this attribute, it has the<br />

underlying data type %ZEN.Datatype.caption. This makes it easy<br />

to localize its text into other languages. See <strong>Zen</strong> Localization.<br />

String containing a CSS color value. This is the color that the<br />

displays when its value falls below<br />

thresholdLower. The default is a pre-defined <strong>Zen</strong> color:<br />

url(#glow-red)<br />

If independentOdometer is true, this is the value to display in<br />

the text box at the center of the gauge.<br />

120 <strong>Using</strong> <strong>Zen</strong>


Charts<br />

9.3.8 <br />

The traffic light consists of three circular lamps in a vertical column. From top to bottom, the lamps<br />

are red, yellow, and green.<br />

When the meter value is at or below thresholdLower, the bottom lamp shows green. At values above<br />

thresholdLower but below thresholdUpper, the center lamp shows yellow. At values at or above<br />

thresholdUpper, the top lamp shows red. This is useful when a large number indicates a condition that<br />

requires attention.<br />

Sometimes a low number indicates a condition that requires attention. If this is the case you can reverse<br />

the sense of a traffic light by inverting the values for rangeLower and rangeUpper. Then the red lamp<br />

indicates low values, and the green lamp indicates high values.<br />

has no unique attributes. It has the usual meter attributes. looks best<br />

when width is half of height. You cannot change the colors for the traffic light (green, yellow, red).<br />

9.4 Charts<br />

Charts, or graphs, are SVG components that represent a series of data points. <strong>Zen</strong> provides several<br />

built-in chart types, including line charts, bar charts, and pie charts. As SVG components, charts have<br />

the layout and style characteristics described in this chapter. However, charts also have many unique<br />

attributes. For a complete explanation, see the next chapter, <strong>Zen</strong> Charts.<br />

<strong>Using</strong> <strong>Zen</strong> 121


<strong>Zen</strong> and SVG<br />

9.5 <br />

The radial navigator is a specialized SVG component that displays the relationship between a set of<br />

data items as a dynamic, radial diagram. There is a central circular hub surrounded by a set of evenly<br />

spaced nodes. As you click on a node at the outer rim of the diagram, it becomes the hub node and the<br />

nodes to which it connects are shown circling it.<br />

You define the nodes in the data set by providing elements inside<br />

the element. For example:<br />

122 <strong>Using</strong> <strong>Zen</strong>


<br />

<br />

<br />

<br />

<br />

Attribute<br />

SVG component<br />

attributes<br />

backgroundStyle<br />

hubStyle<br />

mainLabel<br />

mainLabelStyle<br />

nodeStyle<br />

onselectNode<br />

Description<br />

has the same general-purpose attributes as any<br />

SVG component.<br />

SVG CSS style definition for the background panel. (Styles within<br />

SVG are CSS compliant, but there is a different set of styles<br />

available.)<br />

SVG CSS style definition. Specifies the style for the central hub.This<br />

style must include a fill value, or mouse events within this shape will<br />

not work correctly.<br />

Label text for the central hub.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its<br />

text into other languages. See <strong>Zen</strong> Localization.<br />

SVG CSS style definition. Specifies the style for the mainLabel text.<br />

SVG CSS style definition. Specifies the style for the radial nodes.<br />

This style must include a fill value, or mouse events within this shape<br />

will not work correctly.<br />

Client-side JavaScript expression that runs whenever the user clicks<br />

the mouse on a node shape. Generally this expression invokes a<br />

client-side JavaScript method defined in the page class.<br />

When providing a value for this attribute, use double quotes to<br />

enclose the value and single quotes (if needed) within the JavaScript<br />

expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

selectedIndex<br />

When the onselectNode event is invoked, the selectedIndex contains<br />

the index (0-based) of the currently selected node. If the user clicks<br />

on the central hub node, selectedIndex is -1. When selectedIndex<br />

is –2, this means no node is selected.<br />

<strong>Using</strong> <strong>Zen</strong> 123


<strong>Zen</strong> and SVG<br />

Attribute<br />

title<br />

titleStyle<br />

Description<br />

Title text for the radial navigator.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its<br />

text into other languages. See <strong>Zen</strong> Localization.<br />

SVG CSS style definition. Specifies the style for the title text.<br />

The element is the XML projection of the %ZEN.Auxiliary.radialNode class. <br />

has the following attributes.<br />

Attribute<br />

caption<br />

onclick<br />

Description<br />

Text specifying the caption to display for this radial node.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

Client-side JavaScript expression that runs whenever the user clicks the<br />

mouse on the node shape. When providing a value for this attribute, use<br />

double quotes to enclose the value and single quotes (if needed) within<br />

the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

style<br />

value<br />

SVG CSS style definition for the node. The style must include a fill value,<br />

or mouse events within the node shape will not work correctly.<br />

(Optional) Value associated with this node. The value may be a decimal<br />

or integer number, but it is represented as a string.<br />

When you work with %ZEN.SVGComponent.radialNavigator programmatically, you work with <br />

elements as members of the radialNavigator nodes property, a list collection of<br />

%ZEN.Auxiliary.radialNode objects. Each in the becomes a member<br />

of the nodes collection in radialNavigator, associated with its ordinal position: 1, 2, 3, etc.<br />

124 <strong>Using</strong> <strong>Zen</strong>


9.6 <br />

is an empty SVG component whose contents are filled dynamically by invoking a<br />

runtime callback method that provides SVG content. has the following attributes.<br />

Attribute<br />

SVG<br />

component<br />

attributes<br />

onrender<br />

Description<br />

has the same general-purpose attributes as any SVG<br />

component.<br />

Client-side JavaScript expression. Generally this invokes a client-side<br />

JavaScript method defined in the page class. This method provides the<br />

statements that render the SVG component on the page.<br />

When providing a value for this attribute, use double quotes to enclose<br />

the value and single quotes (if needed) within the JavaScript expression.<br />

For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

The following is an example of an element:<br />

<br />

In the above example, the JavaScript expression invokes the page class doOwnerDraw method with<br />

the object as its argument. The expression represents the page with the built-in variable<br />

zenPage, and the object with the built-in variable zenThis. Elsewhere in the page<br />

class, the doOwnerDraw method could look like this:<br />

<strong>Using</strong> <strong>Zen</strong> 125


<strong>Zen</strong> and SVG<br />

Method doOwnerDraw(svg) [ Language = javascript ]<br />

{<br />

// clear contents of ownerDraw component<br />

}<br />

svg.unrender();<br />

// create a line; add it to the svg component<br />

for (var n = 0; n < 30; n++) {<br />

var line = svg.document.createElementNS(SVGNS,'line');<br />

line.setAttribute('x1',200);<br />

line.setAttribute('y1',100);<br />

line.setAttribute('x2',Math.random() * 400);<br />

line.setAttribute('y2',Math.random() * 200);<br />

line.setAttribute('style','stroke: blue; stroke-width: 2;');<br />

svg.svgGroup.appendChild(line);<br />

}<br />

The SAMPLES namespace offers examples in the page classes ZENDemo.SVGBrowser<br />

and ZENTest.SVGOwnerDrawTest.<br />

You can also create custom SVG components. See Custom Components.<br />

126 <strong>Using</strong> <strong>Zen</strong>


10<br />

<strong>Zen</strong> Charts<br />

This chapter explains how to place a chart on a <strong>Zen</strong> page. Charts represent series of data items by<br />

graphing them, usually across a grid defined by two axes. The following figure shows a line chart.<br />

<strong>Zen</strong> offers several built-in chart types: line charts, bar charts, pie charts, etc. Every chart is an SVG<br />

component as described in the previous chapter, <strong>Zen</strong> and SVG. This means that every chart is derived<br />

from the class %ZEN.SVGComponent.svgComponent. Charts follow the layout and style conventions<br />

for SVG components, but add specific behaviors of their own.<br />

<strong>Using</strong> <strong>Zen</strong> 127


<strong>Zen</strong> Charts<br />

The base chart class %ZEN.SVGComponent.chart defines the data, grid (axes and scales), styles, and<br />

legend used by charts. All charts are plotted onto a virtual coordinate space that measures 100 units<br />

by 100 units. The actual dimensions of this space are determined by the chart height and width values.<br />

Within this virtual space, there is a smaller plot area in which the chart appears. Margins fill the space<br />

around the plot area. Generally you use these margins as space in which to display the labels and legend<br />

for the chart.<br />

The following diagram gives some indication of how chart attributes affect the layout of a chart. The<br />

attributes shown in the diagram include some from the SVG component class<br />

%ZEN.SVGComponent.svgComponent (width, height) and some from the base chart class<br />

%ZEN.SVGComponent.chart (marginTop, bandUpper, legendX). If this were a line chart, there would<br />

also be attributes specific to line charts (chartFilled, chartPivot).<br />

Layout Conventions for <strong>Zen</strong> Charts<br />

The number and variety of chart attributes can seem overwhelming at first. That is why this chapter<br />

begins by introducing the various types of chart, so that you can look at some visual examples and<br />

think about the items you want to display on the <strong>Zen</strong> page, before reading the exact details of how to<br />

display them. Chapter topics appear in this order:<br />

128 <strong>Using</strong> <strong>Zen</strong>


Types of Chart<br />

• Types of Chart<br />

• Providing Data for Charts<br />

• Chart Attributes<br />

• Chart Axes<br />

10.1 Types of Chart<br />

This topic describes and illustrates several types of chart that you can place on the <strong>Zen</strong> page. Each<br />

description includes the unique attributes that define that type of chart. For attributes that all charts<br />

share in common, see the topic Chart Attributes.<br />

10.1.1 Line Charts<br />

A displays one or more data series as a set of lines across a grid. The beginning of this<br />

chapter displays a simple line chart. has the following attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 129


<strong>Zen</strong> Charts<br />

Attribute<br />

Chart<br />

attributes<br />

chartFilled<br />

chartPivot<br />

chartStacked<br />

Description<br />

has the same general-purpose attributes as any chart, plus<br />

the attributes described in this table.<br />

If true, the area under each line is filled (as in an area chart). If false, it<br />

is not filled (as in a line chart).<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

If true, pivot the chart (display categories vertically and values horizontally).<br />

If false, display the chart in typical fashion (categories on the<br />

horizontal axis and values on the vertical axis).<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

chartStacked comes into play if there are multiple data series. If true,<br />

the lines are stacked atop one another (values are additive). If false,<br />

the lines are superimposed (the values are independent). When<br />

chartStacked is true, negative values are ignored.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

130 <strong>Using</strong> <strong>Zen</strong>


Types of Chart<br />

10.1.2 Bar Charts<br />

A displays one or more data series as a set of vertical or horizontal bars. has<br />

the following attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 131


<strong>Zen</strong> Charts<br />

Attribute<br />

Chart<br />

attributes<br />

chartPivot<br />

chartStacked<br />

Description<br />

has the same general-purpose attributes as any chart, plus<br />

the attributes described in this table.<br />

The chart attribute plotToEdge is always treated as false for .<br />

The baseValue is used to plot the bottom of the bars; see Chart<br />

Axes.<br />

If true, pivot the chart (display categories vertically and values horizontally).<br />

If false, display the chart in typical fashion (categories on the<br />

horizontal axis and values on the vertical axis).<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

chartStacked comes into play if there are multiple data series. If true,<br />

the bars at each position along the category axis are stacked atop one<br />

another (values are additive). If "false" the bars appear side by side (the<br />

values are independent). When chartStacked is true, negative values<br />

are ignored.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

132 <strong>Using</strong> <strong>Zen</strong>


Types of Chart<br />

10.1.3 Difference Charts<br />

A is a specialized type of line chart that highlights the difference between two series:<br />

1. The first, reference data series shows ideal or projected values<br />

2. The second data series shows actual values<br />

The shades the area between the two series using the color of the actual data series. To<br />

further distinguish between the series, the chart draws a line representing the reference series across<br />

the shaded area of the chart. This line uses the reference series color; it can take additional styling<br />

from the refLineStyle attribute.<br />

<strong>Using</strong> <strong>Zen</strong> 133


<strong>Zen</strong> Charts<br />

Attribute<br />

Chart<br />

attributes<br />

refLineStyle<br />

Description<br />

has the same general-purpose attributes as any chart, plus<br />

the attributes described in this table.<br />

SVG CSS style definition for the reference line. By default, this line uses<br />

the color assigned to the reference (first) data series, but typically it also<br />

assigns some patterning using refLineStyle. The default is:<br />

stroke-dasharray: 1,1;<br />

The figure above shows:<br />

stroke-dasharray: 3,3; stroke-width: 2px;<br />

10.1.4 High/Low Charts<br />

134 <strong>Using</strong> <strong>Zen</strong>


A can be used to show stock market high-low-close values, or to trace a measured value<br />

along with its high and low ranges to indicate possible error margins. The chart displays a set of bars<br />

as established by three data series:<br />

1. A series of high values sets the top (right) limit of each bar.<br />

2. A series of low values sets the bottom (left) limit of each bar.<br />

3. (Optional) The “closing” values. The chart places a marker on each bar at these values.<br />

Types of Chart<br />

Each low value is assumed to be smaller than its corresponding high value. Each closing value is<br />

assumed to between its corresponding high and low values. The chart uses its first seriesColor value<br />

to plot all bars and marker. It ignores the colors provided for the other series.<br />

Attribute<br />

Chart<br />

attributes<br />

chartPivot<br />

Description<br />

has the same general-purpose attributes as any chart,<br />

plus the attributes described in this table.<br />

The chart attribute plotToEdge is always treated as false for<br />

.<br />

If true, display bars horizontally, as shown in the example above. If false,<br />

display the chart with vertical bars.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

<strong>Using</strong> <strong>Zen</strong> 135


<strong>Zen</strong> Charts<br />

10.1.5 Scatter Diagrams<br />

An plots two or more data series as (x,y) points. This type of chart is sometimes called a<br />

scatter diagram; it is intended to show the raw data distribution for the series. The represents<br />

its data series as follows:<br />

1. The first data series provides the x values<br />

2. The second data series provides correlated y values<br />

3. Any additional data series are plotted as y values correlated to the x values provided by the first<br />

series.<br />

The result is that an always displays one less plot than its number of data series.<br />

has no unique attributes. has the same chart attributes as any chart, except that<br />

markersVisible and plotToEdge are always set to true. Generally you need to manipulate some of the<br />

other chart attributes to produce the desired results. For example:<br />

136 <strong>Using</strong> <strong>Zen</strong>


• The seriesCount value must always be one more than the number of plots you want to display.<br />

This leaves room for the first, x-value series.<br />

• The first data series is not plotted, so the applies series settings beginning with the<br />

second series, not the first. For example:<br />

- The seriesColor list applies to the second, third, and successive series.<br />

- The seriesNames list applies to the second, third, and successive series.<br />

- The markerShapes list applies to the second, third, and successive series.<br />

• A scatter diagram does not appear “scattered” unless you hide the lines between the markers. To<br />

do this, set the plotStyle for an as follows:<br />

plotStyle="stroke-width: 0;"<br />

Types of Chart<br />

10.1.6 Pie Charts<br />

<strong>Using</strong> <strong>Zen</strong> 137


<strong>Zen</strong> Charts<br />

A displays a circle with radial slices representing one series of data values. The chart<br />

adjusts the size of each slice proportionally so that the full set of slices forms a complete circle. The<br />

does not support axes, or grids in the plot area, as for line charts or bar charts.<br />

Attribute<br />

Chart attributes<br />

pieScale<br />

plotBy<br />

showPercentage<br />

Description<br />

has the same general-purpose attributes as any chart,<br />

plus the attributes described in this table.<br />

Decimal value that specifies the scaling factor for the size of the pie<br />

within the chart. The default scaling value is 1.0. A value larger than<br />

1.0 makes the pie bigger relative to the plot area; a value smaller than<br />

1.0 makes the pie smaller.<br />

Specifies how the pie chart will plot its data. Possible values are<br />

"items", "series", or "both". The default is "items". The following topics<br />

describe all the details.<br />

If true, percentage values (rounded to nearest integer) are displayed<br />

as part of the label for each slice. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

The plotBy attribute controls how <strong>Zen</strong> generates a pie chart from the data provided. You<br />

may actually provide multiple series to the . The chart processes all the data series to create<br />

one series, and then displays that series as slices in the chart. plotBy options are as follows.<br />

• "items"<br />

• "series"<br />

• "both"<br />

10.1.6.1 Pie Charts by Item<br />

When the value of plotBy is "items", a plots one slice for every item within the data series.<br />

If you provide multiple data series to an "items" pie chart, each slice of the pie represents the total of<br />

a particular item, summed across all of the data series in the chart.<br />

The following conceptual figure shows how five data series, each containing eight items, would generate<br />

an eight-slice pie chart. Each slice represents the sum of the five values for that item in each<br />

series.<br />

138 <strong>Using</strong> <strong>Zen</strong>


Types of Chart<br />

How <strong>Zen</strong> Plots Pie Charts by Item<br />

When the value of plotBy is "items", labels for the slices are treated as labels. This means<br />

you cannot specify them directly using a chart attribute such as seriesNames. Labels are provided by<br />

a %ZEN.Auxiliary.dataController, if present, or you can provide an onGetLabelY event handler to get<br />

the label values.<br />

10.1.6.2 Pie Charts by Series<br />

When the value of plotBy is "series", multiple series are in use. The plots one slice for<br />

every data series, so the number of slices in the pie chart is seriesCount. Each slice represents the sum<br />

of all the items within one of the series. The seriesNames attribute provides the labels for the slices,<br />

and for the legend. The chart at the beginning of this topic has plotBy set to "series".<br />

The following conceptual figure shows how five data series, each containing eight items, would generate<br />

a five-slice pie chart. Each slice represents the sum of the eight items in that series.<br />

<strong>Using</strong> <strong>Zen</strong> 139


<strong>Zen</strong> Charts<br />

How <strong>Zen</strong> Plots Pie Charts by Series<br />

10.1.6.3 Pie Charts by Both Items and Series<br />

When the value of plotBy is "both", multiple series are in use. The plots one slice for every<br />

item in every data series, so there are seriesCount times seriesSize slices. The base color for each slice<br />

is the associated series color. Alternating slices use dark and normal shades of this color. The chart<br />

legend displays series names; the seriesNames attribute provides these labels. The slices display item<br />

names; the labels are provided by an onGetLabelY event handler, or a data controller.<br />

The following pie chart example compares three series (Products, Services, and Training), each of<br />

which has data items in four categories (America, Asia, Europe, and Africa). The chart has twelve<br />

slices.<br />

140 <strong>Using</strong> <strong>Zen</strong>


Providing Data for Charts<br />

<strong>Zen</strong> Pie Chart from Both Items and Series<br />

10.2 Providing Data for Charts<br />

The data for a chart consists of one or more data series. Each data series that you use for a chart is a<br />

simple array of numeric values. You can provide the data for a chart in one of two ways:<br />

• Invoke a JavaScript method in the page class, by setting the chart’s ongetData attribute.<br />

• Associate the chart with a data controller, by setting the chart’s controllerId attribute.<br />

<strong>Using</strong> <strong>Zen</strong> 141


<strong>Zen</strong> Charts<br />

This topic describes both techniques in detail. First it describes how to limit the data returned by either<br />

technique to the desired number and size of series.<br />

10.2.1 Limiting the Data Set<br />

The following attributes from the base class %ZEN.SVGComponent.chart tell the chart how many series<br />

to use, and how many of the items in each data series to use, when constructing the chart. All types of<br />

chart support these attributes.<br />

Attribute<br />

seriesCount<br />

seriesSize<br />

Description<br />

Positive integer specifying the number of series in the chart. Even if your<br />

data source actually provides a larger number of series, you can trim the<br />

number of displayed series by setting seriesCount to a smaller number.<br />

If the chart does not supply a seriesCount, <strong>Zen</strong> infers the number of<br />

series from the data, as shown in the following figure.<br />

Positive integer specifying the number of items within each data series<br />

to display on this chart. If "", then seriesSize is computed automatically<br />

based on the chart’s data source. Even if the data source actually<br />

provides a larger number of items, you can trim the number of displayed<br />

items by setting seriesSize to a smaller number. If the chart does not<br />

supply a seriesSize, <strong>Zen</strong> infers the size of the series from the data, as<br />

shown in the following figure.<br />

142 <strong>Using</strong> <strong>Zen</strong>


Providing Data for Charts<br />

Data Series Count and Size<br />

10.2.2 <strong>Using</strong> a JavaScript Method<br />

All charts support the ongetData attribute. The value of this attribute is a client-side JavaScript<br />

expression that <strong>Zen</strong> invokes whenever:<br />

• The chart is initially displayed<br />

• The chart’s updateChart method is invoked<br />

For example:<br />

ongetData="return zenPage.getChartData(series);"<br />

Generally the ongetData expression invokes a client-side JavaScript method defined in the page class.<br />

This method becomes the “ongetData event handler” for the chart. In the above example, this method<br />

is called getChartData. The ongetData event handler must accept a single argument, series, and must<br />

assume that this argument contains the 0-based ordinal number of the data series to be plotted. The<br />

method may consist of a switch statement based on the value of this input argument. It must return a<br />

simple array of numeric values for the specified data series.<br />

<strong>Using</strong> <strong>Zen</strong> 143


<strong>Zen</strong> Charts<br />

The following is a sample ongetData event handler that provides random values as a test. You can see<br />

this event handler in the SAMPLES namespace in the template page class ZENTest.SVGChartTest. It<br />

provides the data for charts drawn by page classes that extend the ZENTest.SVGChartTest template,<br />

such as SVGLineChartTest and SVGBarChartTest:<br />

Method getChartData(series) [ Language = javascript ]<br />

{<br />

var chart = zenPage.getComponentById('chart');<br />

var data = new Array(chart.seriesSize);<br />

var value = 50;<br />

}<br />

for (var i = 0; i < chart.seriesSize; i++) {<br />

if (Math.random() > 0.9) {<br />

value += (Math.random() * 50) - 35;<br />

}<br />

else {<br />

value += (Math.random() * 20) - 9;<br />

}<br />

data[i] = value;<br />

}<br />

return data;<br />

10.2.3 <strong>Using</strong> a Data Controller<br />

All charts support the following attributes, which associate the chart with a view on a data controller,<br />

as described in the chapter Model View Controller.<br />

Attribute<br />

controllerId<br />

onnotifyView<br />

Description<br />

Identifies the data controller that provides the data for this chart. The<br />

controllerId value must match the id value provided for that<br />

.<br />

This attribute applies if the chart is associated with a data controller. The<br />

onnotifyView value is a client-side JavaScript expression that is executed<br />

each time the data controller connected to this chart raises an event.<br />

Generally this expression invokes a client-side JavaScript method defined<br />

in the page class.This method becomes the “onnotifyView event handler”<br />

for the chart.<br />

When providing a value for this attribute, use double quotes to enclose<br />

the value and single quotes (if needed) within the JavaScript expression.<br />

For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

144 <strong>Using</strong> <strong>Zen</strong>


If your XData Contents block contains a reference that looks like this:<br />

<br />

Then your XData Contents block may also contain a chart definition that looks like this:<br />

<br />

<br />

Chart Attributes<br />

The chart’s controllerId value must match the id value. The chart takes its seriesSize<br />

from the number of properties in the modelClass.<br />

10.3 Chart Attributes<br />

The base class %ZEN.SVGComponent.chart offers a large number of attributes that you can apply to<br />

a <strong>Zen</strong> chart to control details such as:<br />

• Layout and style — The relative size and characteristics of the background<br />

• Plot area — The part of the chart that displays the data<br />

• Markers — Shapes that highlight the exact data points on a continuous plot<br />

• Legends — A key to the meaning of each plot on the chart<br />

• Titles — Text that labels the chart, and the items on the chart<br />

• User events — How the chart should respond to user actions, such as mouse clicks<br />

• Coordinate axes — Characteristics of the two axes that define most charts<br />

10.3.1 Layout and Style<br />

The following attributes from the base class %ZEN.SVGComponent.chart determine the background<br />

style and the position of the plot area within the chart. When setting values for these attributes, keep<br />

in mind that the chart occupies a virtual coordinate space that measures 100 units by 100 units.<br />

<strong>Using</strong> <strong>Zen</strong> 145


<strong>Zen</strong> Charts<br />

Chart Layout and Style Attributes<br />

Attribute<br />

SVG<br />

component<br />

attributes<br />

backgroundStyle<br />

marginBottom<br />

marginLeft<br />

marginRight<br />

marginTop<br />

Description<br />

A chart has the same general-purpose attributes as any SVG<br />

component. These attributes include the height and width shown in<br />

the above diagram.<br />

SVG CSS style definition. Specifies the style for the background panel.<br />

This is the area outside the plot area but inside the chart component’s<br />

height and width.<br />

Margin to allow from the bottom edge of the background to the bottom<br />

edge of the plot area. X-axis labels or the chart legend usually appear<br />

in this space. Provide an integer value. The default is 10 units.<br />

Margin to allow from the left edge of the background to the left edge<br />

of the plot area. Y-axis labels or the chart legend usually appear in<br />

this space. Provide an integer value. The default is 10 units.<br />

Margin to allow from the right edge of the background to the right edge<br />

of the plot area. Provide an integer value. The default is 2 units.<br />

Margin to allow from the top edge of the background to the top edge<br />

of the plot area. The table title usually appears in this space. Provide<br />

an integer value. The default is 6 units.<br />

10.3.2 Plot Area<br />

The following attributes from the base class %ZEN.SVGComponent.chart determine display conventions<br />

for graphs within the plot area and for the coordinate axes that border the plot area. Also see the next<br />

major topic, Chart Axes.<br />

Attribute<br />

bandLower<br />

bandLowerStyle<br />

bandUpper<br />

bandUpperStyle<br />

Description<br />

Decimal value. If defined, the chart displays a colored band on the<br />

plot area covering the range lower than this value. bandLowerStyle<br />

defines the style of this band.<br />

SVG CSS style definition for the band defined by bandLower.<br />

Decimal value. If defined, the chart displays a colored band on the<br />

plot area covering the range higher than this value. bandUpperStyle<br />

defines the style of this band.<br />

SVG CSS style definition for the band defined by bandUpper.<br />

146 <strong>Using</strong> <strong>Zen</strong>


Chart Attributes<br />

Attribute<br />

gridStyle<br />

labelStyle<br />

labelsVisible<br />

ongetLabelX<br />

Description<br />

SVG CSS style definition. Default style applied to all grid line elements<br />

within the plot area for this chart. If defined, gridStyle overrides any<br />

styles define in the CSS style definition for the page, but gridStyle is<br />

in turn overridden by any styles defined by a specific axis element in<br />

the chart.<br />

SVG CSS style definition. Default style applied to all label elements<br />

for this chart. If defined, labelStyle overrides any styles define in the<br />

CSS style definition for the page, but labelStyle is in turn overridden<br />

by any styles defined by a specific axis element in the chart.<br />

If true, display axis labels for this chart (or slice labels for a pie chart).<br />

If false, hide labels. The default is true.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Client-side JavaScript expression. If the chart provides an ongetLabelX<br />

value, then the ongetLabelX expression is executed to provide the<br />

text for labels on the x-axis.<br />

Generally the ongetLabelX expression invokes a client-side JavaScript<br />

method defined in the page class. This method becomes the<br />

“ongetLabelX event handler” for the chart. It must accept an argument,<br />

value, that contains the 0-based ordinal number of the data point<br />

whose text label is to be returned. It may consist of a switch statement<br />

based on the value of the input argument. It must return a text string.<br />

For example:<br />

ongetLabelX="return zenPage.getXLabels(value);"<br />

When providing a value for an event handler attribute such as<br />

ongetLabelX, use double quotes to enclose the value and single<br />

quotes (if needed) within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

ongetLabelY<br />

Client-side JavaScript expression, as for ongetLabelX.<br />

For pie charts, ongetLabelY is the attribute to use to set slice labels.<br />

<strong>Using</strong> <strong>Zen</strong> 147


<strong>Zen</strong> Charts<br />

Attribute<br />

onrenderPlotArea<br />

plotAreaStyle<br />

plotStyle<br />

plotToEdge<br />

Description<br />

Client-side JavaScript expression. If the chart provides an<br />

onrenderPlotArea value, then the onrenderPlotArea expression is<br />

called by the chart just after it displays its underlying plot area (and<br />

bands) but before it display grid lines and data.<br />

SVG CSS style definition for the plot area panel for this chart.<br />

Default SVG CSS style definition applied to the SVG elements that<br />

are used to plot data for this chart. These elements include the line<br />

in a line chart, or the bar in a bar chart.<br />

Specifies how values should be plotted along a category axis:<br />

• True— plot the first and last values on the edges of the plot area<br />

(as in a line chart)<br />

• False— plot values in the centers of each unit (as in a bar chart)<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

seriesColors<br />

Comma-delimited list of CSS color values to use for data series. The<br />

chart applies these colors to each data series in ordinal order (series<br />

0 gets the first color, series 1 the second color, and so on). If you omit<br />

seriesColors, the default color list is:<br />

"blue,red,green,yellow,orange,plum,purple"<br />

seriesNames<br />

Comma-delimited list of names to use for data series. The chart<br />

applies these names to each data series in ordinal order (series 0<br />

gets the first name, series 1 the second name, and so on). These<br />

names can appear as labels for the series in the legend chart.<br />

The seriesNames attribute has its ZENLOCALIZE datatype parameter<br />

set to 1 (true). This means it is easy to localize its text into other languages.<br />

See <strong>Zen</strong> Localization.The entire list of seriesNames is treated<br />

as one localized string.<br />

10.3.3 Markers<br />

Markers are shapes that are placed at each data point along the chart. If the chart has multiple series,<br />

each series in the chart can use a different shape for its marker. Marker attributes apply only to types<br />

148 <strong>Using</strong> <strong>Zen</strong>


Chart Attributes<br />

of chart that support markers (that is, line charts). The base class %ZEN.SVGComponent.chart offers<br />

the following marker attributes.<br />

Attribute<br />

markerScale<br />

markerShapes<br />

Description<br />

Decimal value that specifies the scaling for markers. A value of 1.0 (or<br />

"") displays markers with the default size. Use a larger value for larger<br />

markers, smaller for smaller markers.<br />

Comma-separated list of shapes to use for each series. It can be convenient<br />

to use a different shape for each series in the chart. This adds<br />

further distinction besides the color of each plot in the chart.The list can<br />

contain any of the following keywords in any order or combination:<br />

• "circle" — a circle<br />

• "down" — a triangle with point down<br />

• "square" — a square<br />

• "up" — a triangle with point up<br />

The default value for markerShapes is "circle,up,down,square"<br />

markerStyle<br />

markersVisible<br />

SVG CSS style definition. Style applied to all marker elements for this<br />

chart. The default is to outline the shape in the same color as the series<br />

plot, and fill the shape with white.<br />

If true, and this chart supports markers, markers will be displayed for<br />

the data points within the chart. If false, no markers are displayed, even<br />

if they are defined. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

10.3.4 Legends<br />

The following attributes from the base class %ZEN.SVGComponent.chart determine the style of the<br />

chart legend and whether or not it should display.<br />

Attribute<br />

legendHeight<br />

Description<br />

If this chart has a legend, this is the height of the legend box (within<br />

the chart coordinate space). If not specified, the chart uses a default<br />

height based on the number of data series.<br />

<strong>Using</strong> <strong>Zen</strong> 149


<strong>Zen</strong> Charts<br />

Attribute<br />

legendLabelStyle<br />

legendStyle<br />

legendVisible<br />

legendWidth<br />

legendX<br />

legendY<br />

Description<br />

SVG CSS style definition for label text within the legend box.<br />

SVG CSS style definition for the background of the legend box.<br />

If true, display a legend for this chart. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

If this chart has a legend, this is the width of the legend box (within<br />

the chart coordinate space). If not specified, the chart assigns a default<br />

width of 15 units.<br />

If this chart has a legend, this is the x-position of the legend box (within<br />

the chart coordinate space). If not specified, the default is 0 (left).<br />

If this chart has a legend, this is the y-position of the legend box (within<br />

the chart coordinate space). If not specified, the default is 0 (top).<br />

10.3.5 Titles<br />

The following attributes from the base class %ZEN.SVGComponent.chart determine the style and<br />

contents of the chart title.<br />

Attribute<br />

title<br />

titleStyle<br />

titleX<br />

titleY<br />

Description<br />

Title text for the chart. Generally you position a chart title outside the plot<br />

area but inside the chart background. See titleX and titleY.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

SVG CSS style definition. Specifies the style for the title text.<br />

If this chart has a title, this is the x-position of the center of the title text<br />

(within the chart coordinate space). If titleX is not specified, the default is<br />

50 (centered between 0 at left and 100 at right in the virtual space).<br />

If this chart has a title, this is the y-position of the bottom line for the title text<br />

(within the chart coordinate space). Descenders (for letters such as 'p' and<br />

'q') fall below this line. If titleY is not specified, the default is 5 (just below<br />

the top of the chart, within the default marginTop value of 6).<br />

150 <strong>Using</strong> <strong>Zen</strong>


Chart Attributes<br />

10.3.6 User Selections<br />

The following attributes control user interactions with the chart.<br />

Attribute<br />

onelementClick<br />

Description<br />

Client-side JavaScript expression that runs whenever the user clicks<br />

on a chart element (such as a marker in a line chart, or bar in a bar<br />

chart).<br />

Generally the onelementClick expression invokes a client-side<br />

JavaScript method defined in the page class. This method becomes<br />

the “onelementClick event handler” for the chart. It must accept an<br />

argument, chart, that represents this chart object. It then calls a<br />

method on this object to determine the identity of the currentlyselected<br />

data point (getSelectedItem) or data series<br />

(getSelectedSeries). Either method returns the 0–based ordinal<br />

number of the item that was selected, or -1 if nothing is currently<br />

selected. For example:<br />

onelementClick="zenPage.chartElementClick(chart);"<br />

If no onelementClick expression is provided, <strong>Zen</strong> uses its own handler<br />

to provide values for selectedItem and selectedSeries.<br />

When providing a value for this attribute, use double quotes to<br />

enclose the value and single quotes (if needed) within the JavaScript<br />

expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

selectedItem<br />

selectedItemStyle<br />

selectedSeries<br />

0–based ordinal number of the currently selected chart element (such<br />

as a marker in a line chart, or bar in a bar chart). This value is -1 if<br />

nothing is currently selected.<br />

SVG CSS style definition for the currently selected item in the chart.<br />

0–based ordinal number of the currently selected series in the chart,<br />

or -1 if no series is currently selected.<br />

<strong>Using</strong> <strong>Zen</strong> 151


<strong>Zen</strong> Charts<br />

10.4 Chart Axes<br />

Axes are essential for determining how chart data will be displayed. The range of axis values (minValue<br />

to maxValue) can be specified using or elements, or <strong>Zen</strong> can determine these values<br />

automatically based on the range of data values. With the exception of pie charts, all <strong>Zen</strong> charts are<br />

plotted using two axes as follows:<br />

• is the category axis; it names the categories in which data is being displayed.<br />

• is the value axis; it displays the value of the data in each category.<br />

In the following example, a element contains and definitions.<br />

<br />

<br />

<br />

<br />

The following attributes from the class %ZEN.Auxiliary.axis are available as attributes of either <br />

or within a chart definition. All of these attributes are optional; <strong>Zen</strong> provides reasonable<br />

defaults for each of them based on the data supplied to the chart.<br />

Chart Axis Attributes<br />

Attribute<br />

baseValue<br />

labelAngle<br />

labelStyle<br />

labelUnits<br />

Description<br />

For charts with filled regions (bar charts), baseValue is a decimal value<br />

that specifies where the base of the filled region should be plotted. If<br />

missing or blank (""), the base is the bottom of the plot area.<br />

Decimal value that specifies the number of degrees by which labels<br />

for this axis should be rotated. The default is 0 (the label text is<br />

horizontal).<br />

SVG CSS style definition for the text labels along this axis.<br />

Decimal value that specifies the amount of space between labels along<br />

this axis. If labelUnits is missing or blank (""), <strong>Zen</strong> automatically<br />

calculates a value based on the data series.<br />

152 <strong>Using</strong> <strong>Zen</strong>


Chart Axes<br />

Attribute<br />

majorGridLines<br />

majorGridStyle<br />

majorUnits<br />

maxValue<br />

minValue<br />

minorGridLines<br />

minorGridStyle<br />

minorUnits<br />

title<br />

Description<br />

If true, grid lines are displayed for each major unit on this axis. If false,<br />

major grid lines are not displayed. The default is true.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

SVG CSS style definition for the major grid lines along this axis.<br />

Decimal value that specifies the amount of space between major grid<br />

lines along this axis. If majorUnits is missing or blank (""), <strong>Zen</strong><br />

automatically calculates a value based on the data series.<br />

Decimal value that specifies the maximum data value along this axis.<br />

If maxValue is missing or blank (""), <strong>Zen</strong> automatically calculates a<br />

value based on the data series.<br />

Decimal value that specifies the minimum value along this axis. If<br />

minValue is missing or blank (""), <strong>Zen</strong> automatically calculates a value<br />

based on the data series.<br />

If true, grid lines are displayed for each minor unit on this axis. If false,<br />

minor grid lines are not displayed. The default is true.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

SVG CSS style definition for the minor grid lines along this axis.<br />

Decimal value that specifies the amount of space between minor grid<br />

lines along this axis. If minorUnits is missing or blank (""), <strong>Zen</strong><br />

automatically calculates a value based on the data series.<br />

Title text for the axis.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

When you work with %ZEN.SVGComponent.chart subclasses programmatically, you work with axes<br />

as the xAxis and yAxis properties of the chart object. Each of these properties is a %ZEN.Auxiliary.axis<br />

object with properties corresponding to the attributes listed above.<br />

<strong>Using</strong> <strong>Zen</strong> 153


11<br />

<strong>Zen</strong> Forms<br />

Forms permit the user to enter data. A <strong>Zen</strong> control is a component that displays application data and<br />

allows the user to edit this data. A <strong>Zen</strong> form is a specialized group component designed to contain<br />

control components. <strong>Zen</strong> forms have the same style and layout attributes as any <strong>Zen</strong> group. Also,<br />

because they are groups, forms may contain any other type of <strong>Zen</strong> component.<br />

Like all <strong>Zen</strong> components, a <strong>Zen</strong> form must be the child of a <strong>Zen</strong> page object. This means that if you<br />

want to provide a form for a <strong>Zen</strong> application, you must create a <strong>Zen</strong> page class that includes a form<br />

component inside the container. Two components are available:<br />

• — A <strong>Zen</strong> group that contains a specific list of control components. These controls may<br />

or may not take their values from a data controller, but their layout is entirely determined by the<br />

definition in XData Contents.<br />

• — An extension of that dynamically injects control components into a group<br />

(or groups) on the <strong>Zen</strong> page. The list of controls may be determined by the properties of an associated<br />

data controller, or by a callback method that generates a list of controls. Layout is automatic,<br />

determined by code internal to the .<br />

11.1 Forms and Controls<br />

The <strong>Zen</strong> library includes a number of controls for use in forms. Many of these controls are wrappers<br />

for the standard HTML controls, while others offer additional functionality. The following figure displays<br />

a form that contains a number of controls, including text fields and radio buttons. This is the<br />

sample form generated by the class ZENDemo.FormDemo in the SAMPLES namespace.<br />

<strong>Using</strong> <strong>Zen</strong> 155


<strong>Zen</strong> Forms<br />

The following figure lists the form and control components that <strong>Zen</strong> provides. Most of the classes<br />

shown in the figure are controls. All of the classes shown in the diagram are in the package<br />

%ZEN.Component, for example %ZEN.Component.form and %ZEN.Component.control. The diagram<br />

shows the inheritance relationships for these classes, and highlights the base classes most frequently<br />

discussed in this book.<br />

156 <strong>Using</strong> <strong>Zen</strong>


Forms and Controls<br />

Class Inheritance Among Form and Control Components<br />

For details about individual controls, see the next chapter, <strong>Zen</strong> Controls.<br />

<strong>Using</strong> <strong>Zen</strong> 157


<strong>Zen</strong> Forms<br />

11.2 User Interactions<br />

The basic interaction between a <strong>Zen</strong> application user and a <strong>Zen</strong> form is as follows:<br />

1. A user interacts with controls on the form<br />

2. <strong>Zen</strong> may validate the data as it is entered<br />

3. A user action indicates that it is time to submit the form<br />

4. <strong>Zen</strong> may validate the data prior to attempting the submit<br />

5. <strong>Zen</strong> interacts with the user to handle any errors it finds<br />

6. When all is well, <strong>Zen</strong> submits data from the form<br />

7. Any of the following might happen next:<br />

• Data from the form may be written to the server<br />

• The same <strong>Zen</strong> page may redisplay<br />

• A different <strong>Zen</strong> page may display<br />

• The same <strong>Zen</strong> page may display, but with components added or changed<br />

11.3 Defining a Form<br />

The <strong>Zen</strong> components and each support the following attributes for defining the<br />

characteristics of a form.<br />

Form Component Attributes<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

autoValidate<br />

Description<br />

A form has the same style and layout attributes as any <strong>Zen</strong> group.<br />

The chapter <strong>Zen</strong> Layout describes them.<br />

If true (the default), automatically invoke this form’s validate method<br />

whenever this form is submitted.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

158 <strong>Using</strong> <strong>Zen</strong>


Defining a Form<br />

Attribute<br />

controllerId<br />

enctype<br />

invalidMessage<br />

Description<br />

If this form is associated with a data controller, the controllerId<br />

attribute identifies the controller that provides the data for this form.<br />

The controllerId value must match the id value provided for that<br />

. See Model View Controller.<br />

(Optional) Specifies a HTML enctype for the form, such as<br />

"multipart/form-data"<br />

Message text that the form validate method displays in an alert box<br />

when the contents of this form are invalid. The default is:<br />

This form contains invalid values.<br />

Please correct the following field(s) and try again.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize<br />

its text into other languages. See <strong>Zen</strong> Localization.<br />

key<br />

nextPage<br />

onchange<br />

(Optional) Identifier used by the OnLoadForm method to load data<br />

for this form. If this form is connected to a dataController, this value<br />

is ignored. The key can be a literal string, or it can contain a <strong>Zen</strong><br />

#()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

URI of the page to display after this form is successfully submitted.<br />

This URI may be overwritten by a specific button on the<br />

form.<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the value<br />

of a control on this form is changed by the user or when the modified<br />

flags are cleared by a call to the form’s clearModified method.<br />

Generally this expression invokes a client-side JavaScript method.<br />

This method becomes the “onchange handler” for the form.<br />

When fired for a control, the onchange expression can use an<br />

argument called control to reference the modified control.<br />

When providing a value for an event handler attribute such as<br />

onchange, use double quotes to enclose the value and single quotes<br />

(if needed) within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

<strong>Using</strong> <strong>Zen</strong> 159


<strong>Zen</strong> Forms<br />

Attribute<br />

ondefault<br />

oninvalid<br />

OnLoadForm<br />

onnotifyView<br />

Description<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />

performs an action that triggers the default action for a form.<br />

Typically this is when the user presses the Enter key within a control<br />

within the form.<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when this form’s<br />

validate method determines that the contents of this form are invalid.<br />

This provides the application with a chance to display a custom<br />

message.<br />

(Optional) Name of a server-side method to call to get values for<br />

this form when it is first displayed. The OnLoadForm value must be<br />

the name of a server-only method in the page class that contains<br />

this form component.<br />

This attribute applies if the form is associated with a data controller.<br />

The onnotifyView value is a client-side JavaScript expression that<br />

is executed each time the data controller connected to this form<br />

raises an event. Generally this expression invokes a client-side<br />

JavaScript method defined in the page class.This method becomes<br />

the “onnotifyView event handler” for the form. See Model View<br />

Controller.<br />

When providing a value for this attribute, use double quotes to<br />

enclose the value and single quotes (if needed) within the JavaScript<br />

expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

onreset<br />

OnSubmitForm<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when this form<br />

is about to be reset. Generally this expression invokes a client-side<br />

JavaScript method.<br />

(Optional) Name of a server-side method to call when this form is<br />

submitted. The OnSubmitForm value must be the name of a<br />

server-only method in the page class that contains this form<br />

component. If no OnSubmitForm value is specified, then the page’s<br />

%OnSubmit method is called instead.<br />

160 <strong>Using</strong> <strong>Zen</strong>


Providing Values for a Form<br />

Attribute<br />

onsubmit<br />

onvalidate<br />

readOnlyMessage<br />

Description<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when this form<br />

is about to be submitted. Generally this expression invokes a<br />

client-side JavaScript method with a Boolean return value. Invoking<br />

this method gives <strong>Zen</strong> a chance to perform client-side validation of<br />

values within the form. If the method returns false, the pending<br />

submit operation will not occur. Note that unlike the HTML onsubmit<br />

event, the onsubmit callback is always called whenever the form is<br />

submitted.<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when this form’s<br />

validate method is called. Generally this expression invokes a<br />

client-side JavaScript method that performs validation.<br />

Message text that the form validate method displays in an alert box<br />

when the user makes an attempt to save a form bound to a readonly<br />

data model. The default readOnlyMessage text is:<br />

This data is read only.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize<br />

its text into other languages. See <strong>Zen</strong> Localization.<br />

11.4 Providing Values for a Form<br />

A form can initially display with blank fields, or you can provide data for some of the fields. Providing<br />

data for a field that the user sees means setting the value property for the associated <strong>Zen</strong> control component,<br />

before you ask <strong>Zen</strong> to display the form. There are several ways to do this:<br />

• Set the value attribute while adding each control to XData Contents.<br />

<br />

• Set the onLoadForm attribute while adding the form to XData Contents.<br />

<br />

• Set value properties from the page’s %OnAfterCreatePage method.<br />

Do ..%SetValueById("Doctor",$G(^formTest("Doctor")))<br />

• On the client side, call the setValue method for each control.<br />

Presumably, once the user begins editing the form, any initial values may change.<br />

<strong>Using</strong> <strong>Zen</strong> 161


<strong>Zen</strong> Forms<br />

11.5 Detecting Modifications to the Form<br />

A <strong>Zen</strong> form component tracks whether or not changes have occurred in any control on the form.<br />

%ZEN.Component.form and %ZEN.Component.control each offers a client-side method called isModified<br />

that tests this programmatically.<br />

A control’s isModified method returns true if the current logical value of the control (the value property)<br />

is different from its original logical value (the originalValue property). With each successive submit<br />

operation, the originalValue for each control acquires its previous value, so that this answer is always<br />

current with respect to the current state of the form.<br />

When you call a form’s isModified method, it invokes isModified for each control on the form, and<br />

if any control returns true, isModified returns true for the form.<br />

Note: The control returns an accurate isModified status when it contains fewer than 50<br />

characters. When the value contains 50 characters or more, the control does not<br />

compute an isModified status.<br />

11.6 Validating a Form<br />

Each <strong>Zen</strong> form has a validate method whose purpose is to validate the values of controls on the form.<br />

If the form’s autoValidate property is true, validate is called automatically each time the form is submitted.<br />

Otherwise, validate may be called explicitly by the application. validate does the following:<br />

1. Calls a form-specific onvalidate event handler, if defined. If this event returns false, <strong>Zen</strong> declares<br />

the form invalid and no further testing occurs.<br />

2. Resets the invalid property of all the form’s controls to false, then tests each control by calling the<br />

control’s validationHandler method. This method, in turn, does the following:<br />

• If the control’s readOnly or disabled properties are true, return true.<br />

• If the control’s required property is true and the control does not have a value (its value is ""),<br />

return false.<br />

• If the control defines an onvalidate event, execute it and returns its value. Otherwise, call the<br />

control’s isValid method. isValid can be overridden by subclasses that wish to provide builtin<br />

validation (such as the dateText control).<br />

3. As the validate method tests each control, the form builds a local array of invalid controls.<br />

4. After the validate method is finished testing the controls, it returns true if the form is valid.<br />

162 <strong>Using</strong> <strong>Zen</strong>


5. If the form contains one or more controls with invalid values, it is invalid. validate performs one<br />

of the following additional steps to handle this case:<br />

• If the form defines an oninvalid event handler:<br />

Execute the handler. This provides the form with a chance to handle the error conditions. The<br />

value returned by the oninvalid event is then returned by the form’s validate method. The<br />

oninvalid handler has an argument named invalidList that receives a JavaScript array containing<br />

the list of invalid controls. For example:<br />

<br />

Where the formInvalid method looks like this:<br />

Method formInvalid(form,list) [ Language = javascript ]<br />

{<br />

return false;<br />

}<br />

• When the form has no oninvalid event handler:<br />

Errors and Invalid Values<br />

validate sets the invalid property to true for each invalid control (which changes their style<br />

to zenInvalid); gives focus to the first invalid control; and displays an error message within<br />

an alert box. The message displayed in the alert box is built from a combination of the form’s<br />

invalidMessage property along with the value returned from each invalid control’s<br />

getInvalidReason method.<br />

11.7 Errors and Invalid Values<br />

Should an error occur while a form is being submitted, or should the form fail validation, <strong>Zen</strong> redisplays<br />

the page containing the form. The user has the opportunity to re-enter any incorrect values and submit<br />

the page again. All of this is extremely easy to set up when adding the or component<br />

to the <strong>Zen</strong> page.<br />

The SAMPLES namespace class ZENTest.FormTest allows you to experience error handling with <strong>Zen</strong><br />

forms as follows:<br />

1. Start your browser.<br />

2. Enter this URI:<br />

http://localhost:57772/csp/samples/ZENTest.FormTest.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché.<br />

3. Ensure that the Name field is empty.<br />

4. Uncheck the Status box.<br />

<strong>Using</strong> <strong>Zen</strong> 163


<strong>Zen</strong> Forms<br />

5. Click Submit.<br />

6. The form’s validate method detects the invalid fields and highlights them with pink.<br />

7. The following alert message displays in the browser.<br />

To generate this message, the form has assembled the following snippets of text. <strong>Zen</strong> offers default<br />

values for these items, so there is no need for you to do anything for the default message to appear.<br />

However, if you wish you can customize them to any extent:<br />

• The message begins with the form’s invalidMessage text.<br />

• For each control that has its required attribute set to true, but contains no entry, the message<br />

lists the control’s label followed by the control’s requiredMessage text.<br />

• For each control that contains an invalid value, the message lists the control’s label followed<br />

by the control’s invalidMessage text.<br />

8. Click OK to dismiss the alert message box.<br />

9. The invalid controls remain highlighted until the user edits them and resubmits the form.<br />

11.8 Processing a Form Submit<br />

The request to submit the contents of a form can be triggered in one of two ways:<br />

• The user clicks a button placed within the form<br />

• The application calls the submit method of the form object in response to a user event:<br />

%form.submit<br />

When a form is submitted, the values of the controls in the form are sent to the server and the<br />

%OnSubmit callback method of the page containing the form is called. Note that the %OnSubmit<br />

callback method is that of the page that contains the form, not of the form itself or of any component<br />

on the form.<br />

%OnSubmit receives an instance of a special %ZEN.Submit object that contains all the submitted<br />

values (there is no page object available during submit processing). <strong>Zen</strong> automatically handles the full<br />

164 <strong>Using</strong> <strong>Zen</strong>


details of the submit operation, including invoking server callbacks and error processing. All forms<br />

are submitted using the HTTP POST submission method.<br />

If you are interested in details of how <strong>Zen</strong> executes a submit operation, the following table lists the<br />

internal events in sequence, organized by user viewpoint, browser-based execution, and server-side<br />

execution. Most of the communication details are handled by the CSP technology underlying <strong>Zen</strong>. For<br />

background information, see the chapter <strong>Zen</strong> Client and Server.<br />

Form Submit Sequence<br />

Processing a Form Submit<br />

User Viewpoint<br />

In the Browser<br />

On the Server<br />

1<br />

User clicks a button<br />

to invoke form<br />

submit<br />

2<br />

Post control values to the<br />

server via the HTTP POST<br />

mechanism<br />

3<br />

4<br />

5<br />

6<br />

7<br />

8<br />

Deserialize data from the<br />

client<br />

Reconstruct DOM based on<br />

new control values<br />

Run the server-side code for<br />

the page<br />

Update server-side DOM<br />

Generate new HTML page<br />

Send new HTML page as<br />

response to HTTP POST<br />

9<br />

10<br />

Render the HTML received<br />

in HTTP POST response<br />

Update client-side DOM to<br />

reflect changes made on<br />

the server<br />

11<br />

User sees new page<br />

<strong>Using</strong> <strong>Zen</strong> 165


<strong>Zen</strong> Forms<br />

11.9 User Login Forms<br />

An application login page presents a special case of a <strong>Zen</strong> form.<br />

See the chapter <strong>Zen</strong> Application Security, topic Controlling Access to Applications.<br />

11.10 Dynamic Forms<br />

A is a specialized type of form that dynamically injects control components into a group<br />

(or groups) on the <strong>Zen</strong> page. Layout is determined automatically by code internal to the .<br />

The list of controls may be determined by the properties of an associated data controller, or by a callback<br />

method that generates a list of controls.<br />

has the attributes listed in the following table.<br />

Attribute<br />

Form component<br />

attributes<br />

controllerId<br />

defaultGroupId<br />

OnGetPropertyInfo<br />

Description<br />

A has the same general-purpose attributes as any <strong>Zen</strong><br />

form. These attributes include the controllerId and onnotifyView<br />

attributes needed to work with a data controller.<br />

If this form is associated with a data controller, the controllerId<br />

attribute identifies the component that provides<br />

the data for this form.The controllerId value must match the id value<br />

for the .<br />

For full details about creating a that uses a data controller,<br />

see the Model View Controller chapter.<br />

(Optional) The id of a group in which to place the controls generated<br />

by this . This provides a way to control layout.<br />

Somewhere inside the , you must specify a group<br />

component (such as or ) with an id that matches<br />

the defaultGroupId. If no defaultGroupId is provided, controls are<br />

added directly to the without being contained in a<br />

group.<br />

(Optional) Name of a server-side method to call to get a list of the<br />

controls to provide on this form. OnGetPropertyInfo provides an<br />

alternative to using a data controller to generate the <br />

The OnGetPropertyInfo value must be the name of a server-only<br />

method in the page class that contains this .<br />

166 <strong>Using</strong> <strong>Zen</strong>


Dynamic Forms<br />

Attribute<br />

onnotifyView<br />

Description<br />

This attribute applies if the form is associated with a data controller.<br />

The onnotifyView value is a client-side JavaScript expression that<br />

is executed each time the data controller connected to this form<br />

raises an event. Generally this expression invokes a client-side<br />

JavaScript method defined in the page class.This method becomes<br />

the “onnotifyView event handler” for the form.<br />

When providing a value for this attribute, use double quotes to<br />

enclose the value and single quotes (if needed) within the JavaScript<br />

expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

For full details about creating a that uses a data controller,<br />

see the Model View Controller chapter.<br />

<strong>Using</strong> <strong>Zen</strong> 167


12<br />

<strong>Zen</strong> Controls<br />

<strong>Zen</strong> controls are the user input elements that you place on a <strong>Zen</strong> form. All controls are <strong>Zen</strong> components,<br />

but <strong>Zen</strong> controls also have unique characteristics derived from their parent class<br />

%ZEN.Component.control.<br />

Most importantly, each control has a value associated with it. value is a property that contains the<br />

current logical value of the control. Each control has the ability to display this value or keep it internally.<br />

<strong>Zen</strong> validates and submits all the control values for a form together, as a unit, according to the rules<br />

described in the previous chapter, <strong>Zen</strong> Forms.<br />

This chapter:<br />

• Describes characteristics shared by all <strong>Zen</strong> controls.<br />

• Identifies variations in layout, style, and behavior for different categories of control:<br />

- Buttons — , , <br />

- Text — , , , <br />

- Choices — , , , , <br />

- Lists — , , , , <br />

- Calendars — , <br />

- Hidden — <br />

- Spreadsheet — <br />

<strong>Using</strong> <strong>Zen</strong> 169


<strong>Zen</strong> Controls<br />

12.1 Control Attributes<br />

All <strong>Zen</strong> controls have the following attributes in common.<br />

Control Component Attributes<br />

Attribute<br />

<strong>Zen</strong> component<br />

attributes<br />

clientType<br />

Description<br />

A control has the same general-purpose attributes as any <strong>Zen</strong><br />

component. The chapter <strong>Zen</strong> Style describes them. The name<br />

attribute for a control has special significance: this name (and not the<br />

id) is associated with the control’s value when the form is submitted.<br />

Indicates the client-side (JavaScript) data type to expect for this<br />

control’s value. By default, a controls treats its value as a string with<br />

no client-side normalization. However, a control can set a value for<br />

clientType to indicate that it has a non-string value on the client side.<br />

Possible values are:<br />

• "string" — The client-side value is a string.<br />

• "boolean" — The client-side value is true or false.<br />

• "integer" — The client-side value is either an integer or '' to<br />

indicate an invalid integer.<br />

• "float" — The client-side value is either a float or '' to indicate<br />

an invalid float.<br />

controlClass<br />

controlStyle<br />

dataBinding<br />

disabled<br />

Name of a CSS style class. When <strong>Zen</strong> lays out this control, it assigns<br />

this value to the primary HTML element displayed for this control.<br />

String containing a CSS style definition. <strong>Zen</strong> applies this style to the<br />

primary HTML element displayed for this control.<br />

If this control is associated with a data controller, this attribute<br />

identifies the specific property within the modelClass<br />

that provides the value for this control. See Model View Controller.<br />

If true, this control is disabled; its appearance is unchanged, but it<br />

does not respond to user actions. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

170 <strong>Using</strong> <strong>Zen</strong>


Control Attributes<br />

Attribute<br />

invalid<br />

invalidMessage<br />

Description<br />

Set to true when the value of this control is known to be invalid. <strong>Zen</strong><br />

form validation logic does this so that <strong>Zen</strong> can display this control in<br />

a way that indicates its value is invalid. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Message text to provide when invalid is true. The default is:<br />

out-of-range or invalid value.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption.This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

—<br />

The next several attributes (names beginning with “on...”) identify<br />

event handlers for user actions relating to a control. In each case,<br />

the value of the attribute is a client-side JavaScript expression that<br />

<strong>Zen</strong> invokes when the related event occurs. Generally this expression<br />

invokes a client-side JavaScript method defined in the page class.<br />

This method becomes known as the “handler” for that specific event.<br />

When providing a value for an event handler attribute, use double<br />

quotes to enclose the value and single quotes (if needed) within the<br />

JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

onblur<br />

onchange<br />

onclick<br />

ondblclick<br />

onfocus<br />

Fired when the control loses focus.<br />

Fired when the value of the control changes. Note that controls fire<br />

this event indirectly; the actual onchange event is sent to a built-in<br />

handler that notifies the form that owns this control of the modification.<br />

Fired when the mouse is clicked on the control.<br />

Fired when the mouse is double-clicked on the control.<br />

Fired when the control is given focus.<br />

<strong>Using</strong> <strong>Zen</strong> 171


<strong>Zen</strong> Controls<br />

Attribute<br />

onkeydown<br />

onkeypress<br />

onkeyup<br />

onmousedown<br />

onmouseout<br />

onmouseover<br />

onmouseup<br />

onsubmit<br />

onvalidate<br />

—<br />

originalValue<br />

readOnly<br />

Description<br />

Fired when the user presses down on a key while this control has<br />

focus. There is a corresponding onkeyup for when the user releases<br />

the key.<br />

Fired after the user has pressed a key (that is, the user has pushed<br />

down and then released the key) while this control has focus.<br />

Fired when a key is released while this control has focus.<br />

Fired when a mouse button is released while within the area of the<br />

control.<br />

Fired when the mouse pointer leaves the area of the control.<br />

Fired when the mouse pointer enters the area of the control.<br />

Fired when a mouse button is pressed while within the area of the<br />

control.<br />

Fired when the form this control belongs to is submitted. This gives<br />

controls a chance to supply or modify the value they submit.<br />

Fired when this control’s value is validated by its parent form.<br />

(End of the list of attributes that identify event handlers.)<br />

Original value for this control before any user modification. It is used<br />

to detect which controls have been modified. This is a special value<br />

in that it is automatically initialized when a form is displayed.<br />

On the client side, do not access this property directly; instead use<br />

the getProperty and setProperty client-side methods. Note that<br />

setting the originalValue property on the client (via setProperty) will<br />

reset it to the current value of this control.<br />

If true, this control is read-only. The user cannot change the value of<br />

this control, but the control still submits its value when the form that<br />

contains it is submitted. The default readOnly value is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

172 <strong>Using</strong> <strong>Zen</strong>


Control Methods<br />

Attribute<br />

required<br />

requiredMessage<br />

Description<br />

If true, this control is required. That is, a user must supply a value for<br />

this control or the default form validation logic will fail.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Message text that the form validate method displays in an alert box<br />

when this control is required and does not have a value. The default<br />

requiredMessage text is:<br />

required.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption.This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

value<br />

Default value displayed within this control. This is a special value in<br />

that it is automatically initialized when a form is displayed. The value<br />

can be a literal string, or it can contain a <strong>Zen</strong> #()# expression. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

On the client side, do not access this property directly; instead use<br />

the getValue and setValue client-side methods.<br />

12.2 Control Methods<br />

Each control has internal methods, which you can study in more detail by viewing the online class<br />

documentation for %ZEN.Component.control and its subclasses.<br />

The most important of these methods are those used to manipulate the value of the control. You can<br />

get and set the value property using the client-side getProperty and setProperty methods; getProperty<br />

and setProperty are available for you to work programmatically with any of the properties listed in<br />

the previous topic, not just value. Calling the setProperty method ensures that all actions relating to<br />

setting the property are also carries out, such as rendering the content within the control on the page.<br />

However, <strong>Zen</strong> controls also define the convenient client-side methods getValue and setValue, which<br />

work only on the value property and save the need to specify which property you wish to change.<br />

<strong>Using</strong> <strong>Zen</strong> 173


<strong>Zen</strong> Controls<br />

12.3 Buttons<br />

<strong>Zen</strong> offers the following button-style controls:<br />

• — The user clicks a button that can trigger further actions<br />

• — The user clicks an image that can trigger further actions<br />

• — The user clicks a button that submits a form<br />

12.3.1 <br />

The component is a simple wrapper for the HTML element.<br />

A <strong>Zen</strong> looks like this:<br />

has the following attributes:<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

caption<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These attributes include the onclick attribute, which determines what<br />

happens when a user clicks the button. If you want the form to be submitted<br />

when the user clicks this button, use the control instead of<br />

.<br />

Text displayed on this button. The above example uses:<br />

<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text into<br />

other languages. See <strong>Zen</strong> Localization.<br />

The caption value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

12.3.2 <br />

The control displays a static image. can be used simply to display an image, or it<br />

can serve as a button if you specify an onclick event for it.<br />

174 <strong>Using</strong> <strong>Zen</strong>


Buttons<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

srcDisabled<br />

streamId<br />

src<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

However, has no associated value.<br />

(Optional) URI of the image to display when the src image is disabled.<br />

(Optional) Stream id of a binary stream object on the server that provides<br />

the data for this image. The streamId value overrides src if present.<br />

This attribute has ZENENCRYPT set to 1 (true) to specify that the streamId<br />

value will be encrypted (using the current session key) when it is sent to<br />

the client. If this value is returned to the server, it will be automatically<br />

decrypted. This makes it possible to place sensitive data on the client for<br />

future processing on the server without letting a user view this data.<br />

Identifies the pathname and filename of the image. The path is relative to<br />

the Caché installation directory. Typically this path identifies the images<br />

subdirectory for your <strong>Zen</strong> application, for example:<br />

<br />

12.3.3 <br />

is a special type of button that submits a form. has the following attributes.<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

caption<br />

action<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These attributes include the onclick attribute, which determines what<br />

happens when a user clicks the button.<br />

Text displayed on this button.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

(Optional) String giving the action code associated with this <br />

button. This value is passed along to the server-side %OnSubmit method<br />

of the page that contains the . If not provided, the default string<br />

is "submit".<br />

<strong>Using</strong> <strong>Zen</strong> 175


<strong>Zen</strong> Controls<br />

Attribute<br />

nextPage<br />

Description<br />

(Optional) URI of the page to display after this form is successfully<br />

submitted. If a button defines a nextPage value, it overrides the<br />

nextPage value for the form that contains the .<br />

12.4 Text<br />

<strong>Zen</strong> offers the following text-style controls:<br />

• — Displays a text label<br />

• — The user inputs text<br />

• — The user inputs multiple lines of text<br />

• — The user inputs a text password<br />

12.4.1 <br />

The control passively displays a static text value. <strong>Zen</strong> submits the along with other<br />

controls on the . has the same attributes as any <strong>Zen</strong> control.<br />

12.4.2 <br />

The <strong>Zen</strong> control is a wrapper around the HTML element. <strong>Zen</strong> <br />

displays a text input box like this:<br />

has the following attributes.<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

maxlength<br />

size<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.These<br />

include the value, a string of text.<br />

Maximum number of characters that the user may enter within this text<br />

control.<br />

Integer indicating the HTML width of the input area for this text control.<br />

The default size is 20.<br />

176 <strong>Using</strong> <strong>Zen</strong>


Text<br />

12.4.3 <br />

The <strong>Zen</strong> control is a wrapper around the HTML element. <strong>Zen</strong> <br />

displays a multi-line text input box, like this:<br />

has the following attributes.<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

cols<br />

rows<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These include the value, a string of text that may or may not<br />

include line break characters, depending on what the user types.<br />

Keep in mind that many browsers do not cope well with long lines of<br />

unbroken text (greater than 4K characters with no white space).<br />

Number of columns in the control. The default is 19.<br />

Number of rows in the control. The default is 2.<br />

12.4.4 <br />

The <strong>Zen</strong> control is a wrapper around the HTML element.<br />

<strong>Zen</strong> displays a text input box for passwords. Any text that the user enters into the <br />

control is echoed as a dot instead of being displayed on the screen. For example:<br />

has the following attributes.<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

maxlength<br />

size<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These include the value, a string of text.<br />

Maximum number of characters that the user may enter within this control.<br />

Integer indicating the HTML width of the input area for this control. The<br />

default size is 20.<br />

<strong>Using</strong> <strong>Zen</strong> 177


<strong>Zen</strong> Controls<br />

12.5 Simple Choices<br />

<strong>Zen</strong> offers the following simple choice controls:<br />

• — The user checks or unchecks a box<br />

• — The user browses to choose a file<br />

• — The user selects one color from a palette<br />

• — The user clicks one in a simple row of radio buttons<br />

• — Radio buttons might be placed anywhere on the page<br />

The difference between and is that is simpler to lay out. Use<br />

for a concise list of choices. Use when you want a more complex page<br />

layout that provides intervening information or images in between the radio button choices, or when<br />

you want to place radio buttons in a vertical group.<br />

12.5.1 <br />

The <strong>Zen</strong> control is a wrapper around the HTML element.<br />

The <strong>Zen</strong> control displays a caption next to the check box and detects user mouse clicks<br />

on the caption text as well as on the box. Unlike an HTML check box, the <strong>Zen</strong> control<br />

always submits a value. <strong>Zen</strong> looks like this:<br />

has the following attributes.<br />

178 <strong>Using</strong> <strong>Zen</strong>


Simple Choices<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

caption<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

has a clientType of "boolean" which means its value is<br />

expressed as "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, and true or false in client-side code. True means the <br />

is currently checked; false means it is unchecked.<br />

Text displayed to the right of the check box. The above example uses:<br />

<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text into<br />

other languages. See <strong>Zen</strong> Localization.<br />

The caption value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

captionClass<br />

Name of a CSS style class to apply to the caption text. The default is:<br />

checkboxCaption<br />

12.5.2 <br />

The component is a simple wrapper for the HTML element.<br />

A <strong>Zen</strong> control looks like this. A user can enter a full pathname in the text field or click<br />

the Browse button to search for the file:<br />

has the following attributes:<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

maxlength<br />

size<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These include the value, a string that is the full pathname of<br />

a file.<br />

Maximum number of characters that the user may enter within this control.<br />

Integer indicating the HTML width of the input area for this control. The<br />

default size is 20.<br />

<strong>Using</strong> <strong>Zen</strong> 179


<strong>Zen</strong> Controls<br />

12.5.3 <br />

The component displays a row of color choices. The user can click on a color to select<br />

it. offers a simple alternative to the complex palette in . A <strong>Zen</strong> <br />

looks like this:<br />

has the following attributes.<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

colorList<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These include the value, a string that identifies the most<br />

recently selected CSS color value.<br />

Comma-separated list of CSS color values to display within the control,<br />

from left to right. The default colorList value is as shown in the example<br />

above:<br />

",black,gray,darkblue,darkred,darkgreen,blue,red,green,yellow,orange,plum,purple,white"<br />

12.5.4 <br />

The control displays a concise row of radio buttons to show a set of choices. A <strong>Zen</strong><br />

looks like this:<br />

12.5.4.1 Logical and Display Values<br />

The simplest way to define a is to provide a valueList for the user to choose from. You can<br />

also add a corresponding displayList for the user to see. These attributes are as follows.<br />

180 <strong>Using</strong> <strong>Zen</strong>


Simple Choices<br />

Attribute<br />

displayList<br />

valueList<br />

Description<br />

(Optional) A comma-separated list of choices to display for this .<br />

displayList applies only if a valueList is defined. Display values may differ<br />

from the actual logical values.<br />

The displayList attribute has its ZENLOCALIZE datatype parameter set to<br />

1 (true). This means it is easy to localize the text into other languages, but<br />

you must ensure that any translated displayList string remains a commaseparated<br />

list. See <strong>Zen</strong> Localization.<br />

Comma-separated list of logical values for the . One of these<br />

logical values becomes the value when the user clicks on the<br />

corresponding button.<br />

You could produce the above sample with the following statement in XData Contents:<br />

<br />

12.5.4.2 Query Attributes<br />

A can indicate a data source for its buttons via an SQL query. offers a number<br />

of attributes for this purpose. When you use this technique, the columns returned by the query determine<br />

what is displayed in the as follows:<br />

• If the %ResultSet has one column, the contents of this column are used as both the logical and<br />

display values within the radioSet.<br />

• If the %ResultSet has two (or more) columns, the contents of the first column supply the logical<br />

value and the contents of the second column supply the display values.<br />

provides the following attributes to support using a query.<br />

<strong>Using</strong> <strong>Zen</strong> 181


<strong>Zen</strong> Controls<br />

Attribute<br />

maxRows<br />

queryClass<br />

queryName<br />

sql<br />

Description<br />

(Optional) If a query is used to provide data, this is the maximum number<br />

of items that will be displayed. The default is 500.<br />

(Optional) The name of the class containing the query. You must also<br />

provide a value for queryName.<br />

(Optional) The name of the class query that will provide the %ResultSet for<br />

this . You must also provide a value for queryClass.<br />

(Optional) Server-side SQL query to get contents of the .<br />

This attribute has the underlying data type %ZEN.Datatype.sql. This means<br />

it cannot be accessed from the client. Its value is encrypted (using the<br />

current session key) when it is sent to the client. If this value is returned to<br />

the server, it is automatically decrypted. This makes it possible to place<br />

sensitive data on the client for future processing on the server, without letting<br />

a user view this data.<br />

For additional details, plus examples, see the <strong>Zen</strong> Tables chapter as follows:<br />

• How to use query attributes with :<br />

- Data Sources (maxRows)<br />

- Specifying an SQL Query (sql)<br />

- Referencing a Class Query (queryClass, queryName)<br />

• How to provide elements within :<br />

- Query Parameters<br />

12.5.4.3 General Attributes<br />

has the following general-purpose attributes.<br />

182 <strong>Using</strong> <strong>Zen</strong>


Simple Choices<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

captionClass<br />

emptyCaption<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These include the value, which is the logical value of the<br />

currently selected button in the set.<br />

(Optional) Name of the CSS style class to apply to captions for radio<br />

buttons within this . The default is the built-in CSS style class<br />

radioSetCaption.<br />

The default caption to use for any buttons within this that<br />

have no display value. If you do not specify an emptyCaption, the default<br />

caption is:<br />

None<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

titleList<br />

Comma-separated list of tooltip text strings for each radio button in the<br />

.<br />

The titleList attribute has its ZENLOCALIZE datatype parameter set to<br />

1 (true). This means it is easy to localize its text into other languages.<br />

See <strong>Zen</strong> Localization.<br />

12.5.5 <br />

The <strong>Zen</strong> control is a wrapper around the HTML element<br />

with some enhanced capabilities. The <strong>Zen</strong> control has the following attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 183


<strong>Zen</strong> Controls<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These include:<br />

• name (not id) establishes the association between radio buttons.You<br />

create a set of associated radio buttons by adding <br />

elements to XData Contents and assigning the same name value to<br />

each that in the set.<br />

• At runtime, value always contains the optionValue of the button in the<br />

set that is currently selected. As soon as the user selects one of the<br />

buttons in the set, <strong>Zen</strong> resets the value of every button in this set to<br />

the optionValue of the selected button. This makes it very easy for<br />

you to determine which button in the set is currently selected, by<br />

programmatically checking the value property of any button in the set.<br />

caption<br />

captionClass<br />

optionValue<br />

The caption text for this . Each button in the set needs a<br />

caption so that the user can distinguish between the choices.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text into<br />

other languages. See <strong>Zen</strong> Localization.<br />

The caption value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

(Optional) Name of the CSS style class to apply to the captions for this<br />

. The default is the built-in CSS style class<br />

radioButtonCaption.<br />

Defines a logical value to associate with this . The<br />

optionValue for each radio button in the set must be unique.<br />

The optionValue can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

12.6 Lists<br />

<strong>Zen</strong> offers the following list controls:<br />

• — You display a list box by using the <strong>Zen</strong> wrapper for HTML <br />

• — You define a <strong>Zen</strong> list box with fixed options for the user to choose<br />

184 <strong>Using</strong> <strong>Zen</strong>


Lists<br />

• — <strong>Zen</strong> generates a list box for you, based on a runtime query<br />

• — You define a <strong>Zen</strong> combo box with fixed options for the user to choose<br />

• — <strong>Zen</strong> generates a combo box for you, based on a runtime query<br />

A list box offers a simple list of options, but a combo box has two parts:<br />

• A text control that displays the current value of the control<br />

• A dropdown list that displays a set of options for the user to select<br />

A combo box dropdown list may appear when activated by the user, for example when the user clicks<br />

the button beside the control. There are a number of ways to reveal the dropdown list. The user can<br />

click on an image or button, or the list can simply appear when the cursor has hovered over the control<br />

for some length of time. You can specify these details when you place a list control on a <strong>Zen</strong> form, or<br />

simply use the default characteristics that <strong>Zen</strong> provides.<br />

12.6.1 <br />

The <strong>Zen</strong> control is a wrapper around the HTML element. <strong>Zen</strong> produces a<br />

list from which the user can select an item.<br />

12.6.1.1 Logical and Display Values<br />

The simplest way to define a list is to provide a valueList for the user to choose from. You<br />

can also add a corresponding displayList for the user to see. These attributes are as follows.<br />

<strong>Using</strong> <strong>Zen</strong> 185


<strong>Zen</strong> Controls<br />

Attribute<br />

displayList<br />

showEmpty<br />

valueList<br />

Description<br />

(Optional) A comma-separated list of values to display for this list.<br />

displayList applies only if a valueList is defined. Display values may differ<br />

from the actual logical values.<br />

The displayList attribute has its ZENLOCALIZE datatype parameter set to<br />

1 (true). This means it is easy to localize the text into other languages, but<br />

you must ensure that any translated displayList string remains a commaseparated<br />

list. See <strong>Zen</strong> Localization.<br />

When true, provides an extra blank row (value "") at the top of its<br />

dropdown box. Typically, this is the desired behavior, so the default<br />

showEmpty value is true.<br />

showEmpty has the underlying data type %ZEN.Datatype.boolean. It has the<br />

value "true" or "false" in XData Contents, 1 or 0 in server-side code, true or<br />

false in client-side code. See Datatype Classes.<br />

Comma-separated list of logical values for the list.<br />

12.6.1.2 Query Attributes<br />

A <strong>Zen</strong> control can indicate a data source for its list via an SQL query. <strong>Zen</strong> offers a<br />

number of attributes for this purpose. When you use this technique, the columns returned by the SQL<br />

query determine what is displayed within the list as follows:<br />

• If the %ResultSet has one column, the contents of this column are used as both the logical and<br />

display values within the dropdown.<br />

• If the %ResultSet has two (or more) columns, the contents of the first column supply the logical<br />

value and the contents of the second column supply the display values.<br />

<strong>Zen</strong> provides the following attributes to support using a query.<br />

186 <strong>Using</strong> <strong>Zen</strong>


Lists<br />

Attribute<br />

maxRows<br />

queryClass<br />

queryName<br />

sql<br />

Description<br />

(Optional) If a query is used to provide data, this is the maximum number<br />

of items that will be displayed. The default is 500.<br />

(Optional) The name of the class containing the query. You must also<br />

provide a value for queryName.<br />

(Optional) The name of the class query that will provide the %ResultSet for<br />

this list. You must also provide a value for queryClass.<br />

(Optional) Server-side SQL query to get contents of the list.<br />

This attribute has the underlying data type %ZEN.Datatype.sql. This means<br />

it cannot be accessed from the client. Its value is encrypted (using the<br />

current session key) when it is sent to the client. If this value is returned to<br />

the server, it is automatically decrypted. This makes it possible to place<br />

sensitive data on the client for future processing on the server, without letting<br />

a user view this data.<br />

For additional details, plus examples, see the <strong>Zen</strong> Tables chapter as follows:<br />

• How to use query attributes with :<br />

- Data Sources (maxRows)<br />

- Specifying an SQL Query (sql)<br />

- Referencing a Class Query (queryClass, queryName)<br />

• How to provide elements within :<br />

- Query Parameters<br />

12.6.1.3 General Attributes<br />

<strong>Zen</strong> has the following general-purpose attributes.<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

size<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.These<br />

include the value, a string indicating the user’s current choice from<br />

the list.<br />

Number of rows to display in the list.<br />

<strong>Using</strong> <strong>Zen</strong> 187


<strong>Zen</strong> Controls<br />

12.6.2 <br />

The <strong>Zen</strong> control displays a list box, whose options may be individually formatted.<br />

The <strong>Zen</strong> control is not a wrapper around HTML . The <strong>Zen</strong> is implemented<br />

using HTML primitives. This allows the to provide functionality not available with HTML<br />

, including:<br />

• Greater control over the contents of the list<br />

• Solutions to problems with Internet Explorer interoperating with CSS<br />

12.6.2.1 Options<br />

The simplest way to define a <strong>Zen</strong> list box is to provide a set of elements inside a <br />

component. The following statements produce the sample list box shown above:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

The element is the XML projection of the %ZEN.Auxiliary.option class and supports the<br />

attributes described in the following table.<br />

188 <strong>Using</strong> <strong>Zen</strong>


Lists<br />

Attribute<br />

style<br />

text<br />

value<br />

Description<br />

(Optional) CSS style to apply to this option.<br />

Display value. This is the text that the user sees in the list box.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

Logical value. This is the value that <strong>Zen</strong> submits for this control when it<br />

submits the form. You must always provide both text and value for each<br />

option in the list.<br />

When you work with %ZEN.Component.listBox programmatically, you work with elements<br />

as members of the options property, a list collection. Each in the becomes a<br />

member of the options collection, associated with an ordinal position: 1, 2, 3, etc.<br />

12.6.2.2 General Attributes<br />

and have the following attributes in common.<br />

List Box Component Attributes<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

listHeight<br />

listWidth<br />

selectedIndex<br />

text<br />

Description<br />

A list box has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These include the list box value, a string of text that represents the<br />

currently selected logical value of the control.<br />

CSS length value. If defined, listHeight overrides the default height of<br />

the list box window, which is 250px.<br />

CSS length value. If defined, listWidth overrides the default width of<br />

the list box window, which is 250px.<br />

0-based index of the currently selected option in the list box.The default<br />

selectedIndex is –1 (nothing is selected).<br />

The display text that corresponds to the currently selected item. Do not<br />

access the text value directly; use getProperty('text') instead.<br />

12.6.3 <br />

A is a specialized type of that presents the user with a list of options obtained<br />

at runtime via an SQL query. Unlike , does not allow you to specify <br />

elements or to set styles for individual options in the list. This is because uses a query<br />

<strong>Using</strong> <strong>Zen</strong> 189


<strong>Zen</strong> Controls<br />

to obtain a dynamic list of options. There are no statically defined options in a , so there<br />

are no elements.<br />

A with an item selected looks like this:<br />

12.6.3.1 Query Attributes<br />

The provides its list by creating, executing, and fetching from a %ResultSet object on<br />

the server. You can specify how to create this %ResultSet object using the attributes that the <br />

inherits from its parent class %ZEN.Auxiliary.QuerySource.<br />

The columns returned by the SQL query determine what is displayed within the list,<br />

as follows:<br />

• If the %ResultSet has one column, the contents of this column are used as both the logical and<br />

display values within the dropdown.<br />

• If the %ResultSet has two (or more) columns, the contents of the first column supply the logical<br />

value and the contents of the second column supply the display values.<br />

The following topics in the chapter <strong>Zen</strong> Tables describe how to use QuerySource attributes:<br />

• How to indicate a data source for a :<br />

- Data Sources (maxRows)<br />

- Specifying an SQL Query (sql)<br />

- Generating an SQL Query ( groupByClause, orderByClause, tableName, whereClause)<br />

190 <strong>Using</strong> <strong>Zen</strong>


Lists<br />

- Referencing a Class Query (queryClass, queryName)<br />

- <strong>Using</strong> a Callback Method (onCreateResultSet, onExecuteResultSet)<br />

• How to provide elements within :<br />

- Query Parameters<br />

12.6.3.2 Display and Logical Values<br />

has an sqlLookup attribute that works in the same way as for . See the<br />

discussion of logical and display values later in this chapter.<br />

12.6.3.3 General Attributes<br />

has the following general-purpose attributes.<br />

Attribute<br />

List box<br />

attributes<br />

Data source<br />

attributes<br />

OnDrawItem<br />

itemCount<br />

sqlLookup<br />

Description<br />

has the same general-purpose attributes as the<br />

component. cannot contain any <br />

elements.<br />

has the same attributes as for specifying<br />

a data source and query parameters.<br />

(Optional) Name of a server-side callback method that is called for<br />

each item in the list before it is displayed. This callback receives the<br />

logical and display values for the current item. It returns the HTML<br />

that is to be displayed within the cell for the given item. OnDrawItem<br />

must be the name of a server-only method in the page class that<br />

contains this list box.<br />

(Read-only) Number of options within the list. This is calculated when<br />

the query for this component is run.<br />

An optional SQL statement that is used under particular conditions.<br />

See the discussion of logical and display values later<br />

in this chapter.<br />

12.6.4 <br />

The <strong>Zen</strong> provides a text field with a dropdown list below it:<br />

<strong>Using</strong> <strong>Zen</strong> 191


<strong>Zen</strong> Controls<br />

The <strong>Zen</strong> control is not a wrapper around HTML . The <strong>Zen</strong> is<br />

implemented using HTML primitives. This allows the to provide functionality not<br />

available with HTML , including:<br />

• The ability to edit values in the text box<br />

• Greater control over the contents of the list<br />

• Solutions to problems with Internet Explorer interoperating with CSS<br />

12.6.4.1 Logical and Display Values<br />

The simplest way to define a is to provide a valueList for the user to choose from. You<br />

can also add a corresponding displayList for the user to see. These attributes are as follows.<br />

Attribute<br />

displayList<br />

valueList<br />

Description<br />

A comma-separated list of values to display for the list in this combo box.<br />

displayList applies only if a valueList is defined. Display values may differ<br />

from the actual logical values.<br />

The displayList attribute has its ZENLOCALIZE datatype parameter set to<br />

1 (true). This means it is easy to localize the text into other languages, but<br />

you must ensure that any translated displayList string remains a commaseparated<br />

list. See <strong>Zen</strong> Localization.<br />

valueList overrides any elements provided within the <br />

(see the discussion following this table).The valueList is a comma-separated<br />

list of logical values for the dropdown list in this . If you provide<br />

a valueList, you must also provide a displayList.<br />

12.6.4.2 Options<br />

Alternatively, you can define a by providing a set of elements inside a <br />

component. is more flexible than a valueList and displayList because it allows you<br />

to apply a CSS style to each of the list entries individually. For example:<br />

192 <strong>Using</strong> <strong>Zen</strong>


Lists<br />

<br />

<br />

<br />

<br />

The element is the XML projection of the %ZEN.Auxiliary.option class and supports the<br />

attributes described in the following table.<br />

Attribute<br />

style<br />

text<br />

value<br />

Description<br />

(Optional) CSS style to apply to this option.<br />

Display value. This is the text that the user sees in the combo box.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

Logical value. This is the value that <strong>Zen</strong> submits for this control when it<br />

submits the form. You must always provide both text and value for each<br />

option in the combo box.<br />

When you work with %ZEN.Component.combobox programmatically, you work with elements<br />

as members of the options property, a list collection. Each in the becomes a<br />

member of the options collection, associated with an ordinal position: 1, 2, 3, etc.<br />

12.6.4.3 General Attributes<br />

and have the following attributes in common.<br />

Combo Box Component Attributes<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

buttonCaption<br />

buttonImage<br />

buttonImageDown<br />

Description<br />

A combo box has the same general-purpose attributes as any <strong>Zen</strong><br />

control. These include the combo box value, a string of text that<br />

represents the currently selected logical value of the control.<br />

Caption used for the button when the comboType is "button".<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its<br />

text into other languages. See <strong>Zen</strong> Localization.<br />

URI of the image to display for the combo button in its normal state.<br />

URI of image to display for the combo button in its down (pressed)<br />

state.<br />

<strong>Using</strong> <strong>Zen</strong> 193


<strong>Zen</strong> Controls<br />

Attribute<br />

buttonTitle<br />

comboType<br />

Description<br />

Popup title used for the dropdown button when comboType is "button"<br />

or "image".<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its<br />

text into other languages. See <strong>Zen</strong> Localization.<br />

How the dropdown box is activated for the combobox:<br />

• "image" indicates that a user-clickable image should be displayed<br />

next to the combo box text box. This is the default.<br />

• "button" indicates that a button should be displayed next to the<br />

combo box text box.<br />

• "timer" indicates that the dropdown should appear shortly after<br />

the user enters a value within the combo box text box.<br />

delay<br />

dropdownHeight<br />

dropdownWidth<br />

editable<br />

maxlength<br />

scrollIntoView<br />

When comboType is "timer", delay specifies how many milliseconds<br />

to wait after user finishes typing before showing the dropdown. The<br />

default is 250 milliseconds.<br />

CSS length value. If defined, dropdownHeight overrides the default<br />

height of the dropdown window, which is 250px.<br />

CSS length value. If defined, dropdownHeight overrides the default<br />

width of the dropdown window, which is 250px.<br />

If true, a user can directly edit the value within the input box as if it<br />

were a text field. The default is false.<br />

editable has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

Maximum number of characters that the user may enter within this<br />

control.<br />

If true, <strong>Zen</strong> uses the JavaScript scrollIntoView function to try and<br />

make visible the currently selected item within the dropdown.<br />

scrollIntoView has the underlying data type %ZEN.Datatype.boolean.<br />

It has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

194 <strong>Using</strong> <strong>Zen</strong>


Lists<br />

Attribute<br />

selectedIndex<br />

size<br />

unrestricted<br />

Description<br />

0-based index of the currently selected option in the dropdown list.<br />

The default selectedIndex is –1 (nothing is selected).<br />

HTML width of the text input area for this control. The default size is<br />

20.<br />

If true, and if editable is also true, values entered by the user may<br />

be used as the value of the control. If false, the value is restricted to<br />

one of the choices within the dropdown list. The default is false.<br />

unrestricted has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

%ZEN.Component.combobox is a subclass of the %ZEN.Component.text control. This means you can<br />

use the various methods defined by the text control to manipulate the text box portion of a <br />

or .<br />

12.6.5 <br />

A is a specialized type of that presents the user with a list of options<br />

obtained at runtime via an SQL query. Unlike , does not allow you to<br />

specify elements or to set styles for individual options in the list. This is because <br />

uses a query to obtain a dynamic list of options. There are no statically defined options in a , so there are no elements.<br />

A with text entered for a search looks like this:<br />

<strong>Using</strong> <strong>Zen</strong> 195


<strong>Zen</strong> Controls<br />

12.6.5.1 Query Attributes<br />

The provides its list by creating, executing, and fetching from a %ResultSet object on<br />

the server. You can specify how to create this %ResultSet object using the attributes that the inherits from its parent class %ZEN.Auxiliary.QuerySource.<br />

The columns returned by the SQL query determine what is displayed within the list, as<br />

follows:<br />

• If the %ResultSet has one column, the contents of this column are used as both the logical and<br />

display values within the dropdown list.<br />

• If the %ResultSet has two (or more) columns, the contents of the first column supply the logical<br />

value and the contents of the second column supply the display values. You can change which<br />

columns are used to provide the logical and display values using the valueColumn and<br />

choiceColumn attributes.<br />

• If the %ResultSet has more than two columns, you can use the displayColumns and columnHeaders<br />

attributes to specify that the dropdown should display multiple columns.<br />

The following topics in the chapter <strong>Zen</strong> Tables describe how to use QuerySource attributes:<br />

• How to indicate a data source for a :<br />

- Data Sources (maxRows)<br />

- Specifying an SQL Query (sql)<br />

- Generating an SQL Query ( groupByClause, orderByClause, tableName, whereClause)<br />

- Referencing a Class Query (queryClass, queryName)<br />

- <strong>Using</strong> a Callback Method (onCreateResultSet, onExecuteResultSet)<br />

• How to provide elements within :<br />

- Query Parameters<br />

12.6.5.2 Query Parameters<br />

The query used to provide the contents of the dropdown list may contain one or more<br />

runtime parameters, such as:<br />

WHERE Name %STARTSWITH <br />

Values for query parameters can be provided in one of the following ways:<br />

• The can define a list, as described in the <strong>Zen</strong> Tables topic Query<br />

Parameters. It is possible to modify the values of these parameters programmatically from the<br />

196 <strong>Using</strong> <strong>Zen</strong>


client; if so, be sure to call the %ZEN.Component.dataCombo method clearCache so that the<br />

dropdown query is re-executed with the new values.<br />

Lists<br />

• If searchKeyLen is set to a non-zero value, and editable is true, then the first searchKeyLen<br />

number of characters in the current contents of the combo input box are used as the value for the<br />

first query parameter. In this case, the first member of the parameters list is ignored. Any additional<br />

query parameters are provided from the parameters list, with one exception: if any parameter value<br />

is equal to "", then the current search key value (that is, the value used for the first parameter)<br />

will also be used for this query parameter.<br />

12.6.5.3 Logical and Display Values<br />

Any list box or combo box has two current values:<br />

• Logical value — its actual stored value as returned by the getValue method<br />

• Display value — the value that the user views and selects in the dropdown list<br />

The <strong>Zen</strong> controls , , and provide a fixed list of logical and display<br />

values. When an application sets the value of one of these controls, it is simple for the control to<br />

identify which display value is associated with the new logical value.<br />

and acquire their values dynamically, so additional steps are needed to<br />

achieve the same result. When an application sets the local value of a control, internally<br />

the tries to find the display value that best matches this logical value. This works differently<br />

on the server and client:<br />

• On the server, executes the SQL statement defined by its sqlLookup attribute<br />

• On the client, the first looks for a match for a given logical value within its dropdown<br />

cache. If it does not find a match, it calls a server method to execute the sqlLookup query.<br />

For example, suppose you want to define a to show a set of Customer names; the display<br />

value will be Name while the logical value will be the ID of the Customer. To do this you define a<br />

with two SQL statements, as follows:<br />

<br />

This definition has the following effects:<br />

1. The query defined by sql is called whenever the dropdown list is displayed. It provides a set of<br />

logical (ID) and display (Name) values. The parameter gets its value from the contents of the<br />

text field at the time when the dropdown appears; the value of searchKeyLen<br />

<strong>Using</strong> <strong>Zen</strong> 197


<strong>Zen</strong> Controls<br />

indicates that up to the first 10 characters will be used. The remembers the results<br />

of the last query in a local cache.<br />

2. The query defined by sqlLookup is used to find a specific display value for a specific logical value.<br />

When this query is executed, the logical value of the control is provided as a query input parameter<br />

(a within the SQL statement). This query must return a single row containing a display value.<br />

3. The sqlLookup query is also executed when the application tries to set the logical value of this<br />

at runtime, and the answer is not in the cache from item 1.<br />

The sqlLookup attribute has the underlying data type %ZEN.Datatype.sql. This means it cannot be<br />

accessed from the client. Its value is encrypted (using the current session key) when it is sent to the<br />

client. If this value is returned to the server, it is automatically decrypted. This makes it possible to<br />

place sensitive data on the client for future processing on the server, without letting a user view this<br />

data.<br />

12.6.5.4 General Attributes<br />

has the following general-purpose attributes.<br />

Attribute<br />

Combo box<br />

attributes<br />

Data source<br />

attributes<br />

auxColumn<br />

choiceColumn<br />

Description<br />

has the same general-purpose attributes as the<br />

component. There can be no statically defined options,<br />

so does not support the displayList and valueList<br />

attributes. A also cannot contain any elements.<br />

has the same attributes as for specifying<br />

a data source and query parameters.<br />

If there are multiple data columns displayed in the dropdown list,<br />

auxColumn is the 1-based column number of the column that will<br />

provide an additional auxiliary value for this control. auxColumn<br />

provides a way to supply an additional value that is not the display or<br />

logical value. If the auxColumn value is not a valid column number,<br />

no auxiliary data is provided. The default auxColumn value is 0.<br />

If there are multiple data columns displayed within the dropdown list,<br />

choiceColumn is the 1-based column number of the column that will<br />

provide the display value for this control. The default choiceColumn<br />

value is 2. If the supplied choiceColumn value is greater than the<br />

number of columns in the query, the second column is used.<br />

198 <strong>Using</strong> <strong>Zen</strong>


Lists<br />

Attribute<br />

columnHeaders<br />

displayColumns<br />

loadingMessage<br />

Description<br />

If defined, columnHeaders is a comma-separated list of column<br />

headers to display in the dropdown list.<br />

The columnHeaders attribute has its ZENLOCALIZE datatype<br />

parameter set to 1 (true). This means it is easy to localize its text into<br />

other languages. See <strong>Zen</strong> Localization.<br />

(Optional) If there are multiple data columns in the %ResultSet for the<br />

, displayColumns can provide a comma-separated list<br />

of 1–based column numbers. This list identifies which columns out of<br />

the %ResultSet should be displayed.<br />

This message is temporarily displayed while a server-side query is<br />

running to populate the list. The default is:<br />

$$$Text("Loading...","%ZEN");<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

multiColumn<br />

searchKeyLen<br />

showEmpty<br />

If true, and if the result set contains more than 2 columns, display<br />

multiple columns in the dropdown box. The default is true.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

If non-zero, searchKeyLen is the maximum number of search<br />

characters for <strong>Zen</strong> to take from the combo input box and pass as a<br />

parameter to the SQL query that provides the contents of the dropdown<br />

list. If zero, the contents of the input box are not used as a query<br />

parameter. The default is 0.<br />

When true, the outputs an extra blank row (value "") at<br />

the top of its dropdown box. Typically, this is the desired behavior, so<br />

the default showEmpty value is true. Regardless of the showEmpty<br />

value, this blank row does not display when the has its<br />

control component attribute required set to true.<br />

showEmpty has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side<br />

code, true or false in client-side code. See Datatype Classes.<br />

<strong>Using</strong> <strong>Zen</strong> 199


<strong>Zen</strong> Controls<br />

Attribute<br />

sqlLookup<br />

valueColumn<br />

Description<br />

An optional SQL statement that is used under particular conditions.<br />

See Logical and Display Values, above.<br />

(Optional) If there are multiple data columns in the %ResultSet for the<br />

, valueColumn identifies the 1-based column number<br />

of the column that will provide the logical value for this control. The<br />

default valueColumn is 1. If the supplied valueColumn value is greater<br />

than the number of columns in the query, the first column is used.<br />

12.6.5.5 Display Sequence<br />

If you are interested in details of how <strong>Zen</strong> displays the , the following table lists the<br />

internal events in sequence, organized by user viewpoint, browser-based execution, and server-side<br />

execution. Most of the communication details are handled by the CSP technology underlying <strong>Zen</strong>. For<br />

background information, see the chapter <strong>Zen</strong> Client and Server.<br />

200 <strong>Using</strong> <strong>Zen</strong>


Lists<br />

Display Sequence<br />

User Viewpoint<br />

In the Browser<br />

On the Server<br />

1<br />

Select the dropdown<br />

2<br />

3<br />

Dropdown is activated<br />

Send hyperevent to the<br />

server to execute SQL<br />

4<br />

5<br />

Receive hyperevent to<br />

execute SQL<br />

Send hyperevent response<br />

(consisting of JavaScript code)<br />

to populate the dropdown unit<br />

6<br />

Server fills the dropdown<br />

list<br />

7<br />

8<br />

List fills with items<br />

User selects an item<br />

9<br />

10<br />

11<br />

Dropdown item is selected<br />

Call client-side select event<br />

handler<br />

Send hyperevent to the<br />

server to start a<br />

<strong>Zen</strong>Method<br />

12<br />

13<br />

14<br />

Receive hyperevent to start<br />

<strong>Zen</strong>Method<br />

Update server-side DOM<br />

Send hyperevent response<br />

(consisting of JavaScript code)<br />

to synchronize client DOM<br />

with server DOM<br />

15<br />

Update client-side DOM to<br />

reflect changes made on<br />

the server during the<br />

<strong>Zen</strong>Method<br />

<strong>Using</strong> <strong>Zen</strong> 201


<strong>Zen</strong> Controls<br />

16<br />

User Viewpoint<br />

In the Browser<br />

Update visual presentation<br />

of DOM-bound<br />

components to match new<br />

client-side DOM<br />

On the Server<br />

17<br />

Form fields get filled<br />

in based on the<br />

selection<br />

12.7 Calendars<br />

<strong>Zen</strong> offers the following date selection controls:<br />

• — The user selects dates from a popup calendar<br />

• — The user can enter text or select a date<br />

12.7.1 <br />

The component displays a navigable calendar, one month at a time. The user can view and<br />

select dates from this calendar. A initially displays with the current date highlighted in<br />

bold (7 in the example below) and the currently selected date in bold with a yellow background color<br />

(14 in the example below). A <strong>Zen</strong> looks like this:<br />

has the following attributes.<br />

202 <strong>Using</strong> <strong>Zen</strong>


Calendars<br />

Attribute<br />

Control<br />

component<br />

attributes<br />

dayList<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> control.<br />

These attributes include the value, a string in the format<br />

YYYY-MM-DD (it has the datatype %Timestamp on the server).<br />

Comma-separated list of day abbreviations to show at the top of the<br />

calendar. The default value is:<br />

$$$Text("S,M,T,W,T,F,S");<br />

The dayList attribute has its ZENLOCALIZE datatype parameter set to<br />

1 (true). This means it is easy to localize its text into other languages<br />

and permits use of the $$$Text macro as shown in the default dayList<br />

value. See <strong>Zen</strong> Localization.<br />

endYear<br />

firstDayOfWeek<br />

fixedMonth<br />

gapWidth<br />

maxDate<br />

Four-digit end year number for the year selector in the calendar. If not<br />

defined, the default is the year portion of maxDate, if defined. Otherwise,<br />

the default endYear is 30 years from now.<br />

Number (Sunday=0, Saturday=6) that specifies which day of the week<br />

is displayed as the starting day of the week. The default is 0 (Sunday).<br />

If true, this calendar displays a single month and provides no way for<br />

the user to change month and year. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

HTML length value giving the size of the gap between the month and<br />

year indicators at the top of the calendar. Setting this provides a way<br />

to adjust the width of the calendar.The above example uses the default<br />

of 40px.<br />

(Optional) String in the format YYYY-MM-DD (datatype %Timestamp on<br />

the server). If specified, this is the latest date that the will<br />

accept as its value. The maxDate value does not affect which years<br />

are displayed by the calendar unless endYear is omitted.<br />

The value supplied for maxDate can be a literal string, or it can contain<br />

a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

<strong>Using</strong> <strong>Zen</strong> 203


<strong>Zen</strong> Controls<br />

Attribute<br />

minDate<br />

month<br />

monthList<br />

Description<br />

(Optional) String in the format YYYY-MM-DD (datatype %Timestamp on<br />

the server). If specified, this is the earliest date that the will<br />

accept as its value. The minDate value does not affect which years are<br />

displayed by the calendar unless startYear is omitted.<br />

The value supplied for minDate can be a literal string, or it can contain<br />

a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

Number (January=1, December=12) that specifies which month of the<br />

year is currently displayed by the calendar. This is not the same as the<br />

current value, which includes a day and year, which can<br />

include time, and whose month may be different.<br />

Comma-separated list of month names to display in the list of months<br />

that the user can choose from the calendar. The default value is:<br />

$$$Text("January,February,March,April,May,June,July,August,September,October,November,December");<br />

monthList has its ZENLOCALIZE datatype parameter set to 1 (true).<br />

This means it is easy to localize its text into other languages and permits<br />

use of the $$$Text macro as shown in the default monthList value. See<br />

<strong>Zen</strong> Localization.<br />

showTime<br />

startYear<br />

If true, this component displays a text entry field below the main calendar.<br />

In the example above, showTime is true. The default is false.<br />

The user can enter a time of day in the showTime field using the 24–hour<br />

time format HH:MM:SS. When the form is submitted, the <br />

value accepts both date and time values in the following ODBC/JDBC<br />

timestamp format: YYYY-MM-DD HH:MM:SS<br />

showTime has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

Four-digit start year number for the year selector in the calendar. If not<br />

defined, the default is the year portion of minDate, if defined. Otherwise,<br />

the default startYear is 10 years ago.<br />

204 <strong>Using</strong> <strong>Zen</strong>


Calendars<br />

Attribute<br />

timeCaption<br />

Description<br />

Caption text for the showTime field. The default value is shown in the<br />

example above:<br />

$$$Text("Time:");<br />

timeCaption has its ZENLOCALIZE datatype parameter set to 1 (true).<br />

This means it is easy to localize its text into other languages and permits<br />

use of the $$$Text macro as shown in the default timeCaption value.<br />

See <strong>Zen</strong> Localization.<br />

year<br />

Four-digit number that specifies which year is currently displayed by<br />

the calendar. This is not the same as the current value,<br />

which includes a day and month, which can include time, and whose<br />

year may be different.<br />

12.7.2 <br />

The control is essentially a combo box. It displays a text box as well as a button that, when<br />

pressed, displays a popup calendar. When the user enters a value into the text area of this control, <strong>Zen</strong><br />

either converts this value into the closest matching date value, or it displays an invalid date message.<br />

Note:<br />

always normalizes the date format to YYYY-MM-DD. There is no alternate<br />

format for this built-in control.<br />

A <strong>Zen</strong> component looks like this:<br />

has the following attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 205


<strong>Zen</strong> Controls<br />

Attribute<br />

Control component<br />

attributes<br />

invalidDateMessage<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong><br />

control. These attributes include the value, a string in<br />

the format YYYY-MM-DD (it has the datatype %Timestamp on the<br />

server).<br />

Message displayed by control when the date entered by the user<br />

fails validation. The default is:<br />

$$$Text("Invalid Date","%ZEN");<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption.This makes it easy to localize<br />

its text into other languages. See <strong>Zen</strong> Localization.<br />

maxDate<br />

minDate<br />

showTime<br />

(Optional) String in the format YYYY-MM-DD (datatype %Timestamp<br />

on the server). If specified, this is the latest date that the <br />

will accept as its value. The maxDate value does not affect which<br />

years are displayed by the calendar unless endYear is omitted.<br />

The value supplied for maxDate can be a literal string, or it can<br />

contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

(Optional) String in the format YYYY-MM-DD (datatype %Timestamp<br />

on the server). If specified, this is the earliest date that the <br />

will accept as its value. The minDate value does not affect<br />

which years are displayed by the calendar unless startYear is<br />

omitted.<br />

The value supplied for minDate can be a literal string, or it can<br />

contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

If true, this component displays a text entry field below the main<br />

calendar. In the example above, showTime is true. The default is<br />

false.<br />

The user can enter a time of day in the showTime field using the<br />

24–hour time format HH:MM:SS. When the form is submitted, the<br />

value accepts both date and time values in the following<br />

ODBC/JDBC timestamp format: YYYY-MM-DD HH:MM:SS<br />

showTime has the underlying data type %ZEN.Datatype.boolean. It<br />

has the value "true" or "false" in XData Contents, 1 or 0 in serverside<br />

code, true or false in client-side code. See Datatype Classes.<br />

206 <strong>Using</strong> <strong>Zen</strong>


Hidden Items<br />

Attribute<br />

size<br />

Description<br />

HTML width of the text input area for this control. The default is 15.<br />

Note:<br />

When you set the value property of a dateText control programmatically, this bypasses the<br />

date matching function that <strong>Zen</strong> provides when the user sets the date by typing text in the<br />

input field.<br />

12.8 Hidden Items<br />

The <strong>Zen</strong> control is a wrapper around the HTML element. The<br />

control is present in the form, and has a value associated with it, but is never visible to the<br />

user. The value can be changed programmatically on the client or server side. When the form is submitted,<br />

the values of any controls are submitted along with all the others.<br />

has the same general-purpose attributes as any <strong>Zen</strong> control. It has no additional attributes.<br />

12.9 Spreadsheet<br />

The control displays a two-dimensional, editable grid, similar to a spreadsheet. When the<br />

user clicks in a cell, an edit control appears in the cell and the user can edit the cell contents. The user<br />

presses Enter to save changes. A with a newly-edited cell looks like this:<br />

You can create a in one of the following ways:<br />

• Specify a data set, rows, and columns as described below<br />

• Associate the with a Model View Controller<br />

<strong>Using</strong> <strong>Zen</strong> 207


<strong>Zen</strong> Controls<br />

12.9.1 Data Set<br />

The data displayed within the is supplied by a %ZEN.Auxiliary.dataSet object. dataSet is<br />

a special data container object that is used to define one-, two-, or three-dimensional data in a form<br />

that can be easily transported between the server and client.<br />

When a object is first created, it automatically creates a two–dimensional dataSet object<br />

with the number of rows (dimension 1) and columns (dimension 2) specified by the number of<br />

and entries within the definition in XData Contents. The following<br />

example specifies four rows and four columns for the initial dataSet object:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

An application can change the size and contents of the initial dataSet object by defining a server-side<br />

callback method. You can specify the name of this callback method using the <br />

OnCreateDataSet attribute, as in the example above. The OnCreateDataSet value must be the name<br />

of a server-side callback method defined within the page class that contains the control.<br />

In the above example, this method name is CreateDS. The OnCreateDataSet callback method is called<br />

once, when the object is first created on the server and before the is first<br />

displayed.<br />

The signature of the OnCreateDataSet callback method must look like this:<br />

Method CreateDS(<br />

pGrid As %ZEN.Component.dynaGrid,<br />

pDataSet As %ZEN.Auxiliary.dataSet) As %Status<br />

Where:<br />

• pGrid is the dynaGrid object that is invoking the callback.<br />

• pDataSet is the dataSet object associated with the dynaGrid object.<br />

• The method returns a %Status value indicating success or failure.<br />

Typically a OnCreateDataSet callback method looks like this:<br />

208 <strong>Using</strong> <strong>Zen</strong>


Spreadsheet<br />

Method CreateDS(<br />

pGrid As %ZEN.Component.dynaGrid,<br />

pDataSet As %ZEN.Auxiliary.dataSet) As %Status<br />

{<br />

// make sure dataSet is cleared out<br />

Do pDataSet.%Clear()<br />

// fill in contents of dataSet<br />

// This is a 2-D data structure<br />

// row labels (dimension 1)<br />

Do pDataSet.%SetLabel("Boston",1,1)<br />

Do pDataSet.%SetLabel("New York",2,1)<br />

Do pDataSet.%SetLabel("Chicago",3,1)<br />

Do pDataSet.%SetLabel("Miami",4,1)<br />

// column labels (dimension 2)<br />

Do pDataSet.%SetLabel("Cars",1,2)<br />

Do pDataSet.%SetLabel("Trucks",2,2)<br />

Do pDataSet.%SetLabel("Trains",3,2)<br />

Do pDataSet.%SetLabel("Planes",4,2)<br />

// get size of dataSet<br />

Set rows = pDataSet.%GetDimSize(1)<br />

Set cols = pDataSet.%GetDimSize(2)<br />

// fill in initial data values<br />

For r=1:1:rows {<br />

For c=1:1:cols {<br />

Set value = 0<br />

Do pDataSet.%SetValue(value,r,c)<br />

}<br />

}<br />

}<br />

Quit $$$OK<br />

The above example defines a two–dimensional dataSet object with four rows and four columns. It<br />

supplies labels for the rows and columns and then loops over the cells to provide initial values for the<br />

cells.<br />

If the OnCreateDataSet callback changes the dataSet object to contain three dimensions, this gives<br />

the the ability to move among “pages” of data. Each page is displayed as a two-dimensional<br />

grid that represents the currently visible “page.” The following figure illustrates this data model.<br />

Note:<br />

The next several topics provide details regarding the label attributes shown in the figure. See<br />

, , and Dynamic Grid Attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 209


<strong>Zen</strong> Controls<br />

Data Model for the Dynamic Grid Control<br />

If there are pages in the , the gridLabel cell provides navigation information as follows.<br />

Click on the > symbol for the next page. The number indicates<br />

which page you are currently viewing:<br />

12.9.2 Methods<br />

Since the dataSet object is designed to work on either the server or the client, it provides local APIs<br />

for both environments. The following table lists the server-side (ObjectScript) methods. For further<br />

details, and to see the list of client-side (JavaScript) methods, see the class documentation for<br />

%ZEN.Auxiliary.dataSet.<br />

210 <strong>Using</strong> <strong>Zen</strong>


Spreadsheet<br />

Note:<br />

When you work with %ZEN.Component.dynaGrid programmatically, on the server side you<br />

can access the dataSet object via the dataSet property of the dynaGrid object. On the client,<br />

you cannot access the dataSet directly; you must the dynaGrid object’s getDataSet method<br />

to get the dataSet object.<br />

Server Method<br />

%Clear<br />

%GetArray<br />

%GetDimensions<br />

%GetDimSize<br />

%GetLabel<br />

Description<br />

Clear the contents of the dataSet (set every cell to "") without<br />

changing its size or number of dimensions.<br />

Gets the contents of the dataSet as a multidimensional array,<br />

subscripted by the 1–based dimensional addresses of the cells<br />

(row, column, page). This array is passed to %GetArray by<br />

reference.<br />

Returns the number of dimensions within the dataSet.<br />

Receives a 1–based number identifying a dimension (row, column,<br />

page) and returns the number of cells in that dimension.<br />

Receives two numbers:<br />

• 1–based number identifying a cell position within a dimension<br />

• 1–based number identifying the dimension (row, column, page)<br />

%GetLabel returns the value of the label at the specified position.<br />

%GetValue<br />

%SetArray<br />

Receives up to three 1–based numbers identifying a specific cell<br />

in the grid (row, column, page). Gets the value of the cell at that<br />

position.<br />

Receives up to four arguments:<br />

• A multidimensional array, passed by reference, and subscripted<br />

by the 1–based dimensional addresses of the cells (row, column,<br />

page).The local array must have the same dimensionality<br />

as the dataSet and must have the correct number and type of<br />

subscripts.<br />

• Up to three 1–based numbers identifying the number of cells<br />

in each dimension of the grid (row, column, page).<br />

%SetArray copies the contents of the array into the dataSet.<br />

%SetDimensions<br />

Sets the number of dimensions within the dataSet to 1, 2, or 3.<br />

<strong>Using</strong> <strong>Zen</strong> 211


<strong>Zen</strong> Controls<br />

Server Method<br />

%SetLabel<br />

Description<br />

Receives three arguments:<br />

• String that specifies a label.<br />

• 1–based number identifying a cell position within a dimension<br />

• 1–based number identifying the dimension (row, column, page)<br />

%SetLabel copies the string to the label at the specified position.<br />

%SetValue<br />

Receives up to four arguments:<br />

• String that specifies a value.<br />

• Up to three 1–based numbers identifying a specific cell in the<br />

grid (row, column, page).<br />

%SetValue sets the value of the cell at the indicated position.<br />

%SetValue also updates the dimension size, if needed.<br />

12.9.3 <br />

A with dimensions greater than zero must contain one or more and <br />

elements to define the initial dimensions of the grid. defines dimension 1 of a one-<br />

, two-, or three-dimensional .<br />

The element is the XML projection of the %ZEN.Auxiliary.gridRow class. <br />

supports the attributes described in the following table.<br />

Attribute<br />

height<br />

hidden<br />

label<br />

Description<br />

HTML height value to apply to this row, such as 0.3in or 3%.<br />

If true, this row is not displayed. The default is false.<br />

hidden has the underlying data type %ZEN.Datatype.boolean. It has the value<br />

"true" or "false" in XData Contents, 1 or 0 in server-side code, true or false<br />

in client-side code. See Datatype Classes.<br />

Default text label for the row.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

212 <strong>Using</strong> <strong>Zen</strong>


Spreadsheet<br />

Attribute<br />

readOnly<br />

rowName<br />

style<br />

Description<br />

If true, cells in this row are read-only; the user cannot edit them.The default<br />

is false.<br />

readOnly has the underlying data type %ZEN.Datatype.boolean. It has the<br />

value "true" or "false" in XData Contents, 1 or 0 in server-side code, true<br />

or false in client-side code. See Datatype Classes.<br />

Logical name of the row.<br />

CSS style to apply to cells in this row, for example:<br />

color: red;<br />

If there is a column style and a row style active for a given cell, the row<br />

style is applied before the column style.This means the column style might<br />

override the row style.<br />

title<br />

Help text displayed when mouse hovers over this row. If there is a row title<br />

and a column title active for a given cell, the column title overrides the row<br />

title.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

When you work with %ZEN.Component.dynaGrid programmatically, you work with elements<br />

as members of the dynaGrid property called rows. This is a list collection of %ZEN.Auxiliary.gridRow<br />

objects. Each provided in the original definition in XData Contents becomes<br />

a member of the rows collection, associated with its ordinal position in the : 1, 2, 3, etc.<br />

12.9.4 <br />

A with dimensions greater than zero must contain one or more and <br />

elements to define the initial dimensions of the grid. defines dimension 2 of a<br />

two- or three-dimensional .<br />

The element is the XML projection of the %ZEN.Auxiliary.gridColumn class. <br />

supports the attributes described in the following table.<br />

<strong>Using</strong> <strong>Zen</strong> 213


<strong>Zen</strong> Controls<br />

Attribute<br />

columnName<br />

hidden<br />

label<br />

readOnly<br />

style<br />

Description<br />

Logical name of the column.<br />

If true, this column is not displayed. The default is false.<br />

hidden has the underlying data type %ZEN.Datatype.boolean. It has the<br />

value "true" or "false" in XData Contents, 1 or 0 in server-side code, true<br />

or false in client-side code. See Datatype Classes.<br />

Default text label for the column.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

If true, cells in this column are read-only; the user cannot edit them.The<br />

default is false.<br />

readOnly has the underlying data type %ZEN.Datatype.boolean. It has the<br />

value "true" or "false" in XData Contents, 1 or 0 in server-side code, true<br />

or false in client-side code. See Datatype Classes.<br />

CSS style to apply to cells in this column, for example:<br />

color: red;<br />

If there is a row style and a column style active for a given cell, the row<br />

style is applied before the column style. This means the column style<br />

might override the row style.<br />

title<br />

width<br />

Help text displayed when mouse hovers over this column. If there is a<br />

row title and a column title active for a given cell, the column title overrides<br />

the row title.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

HTML width value to apply to this column, such as 0.3in or 3%.<br />

When you work with %ZEN.Component.dynaGrid programmatically, you work with <br />

elements as members of the dynaGrid property called columns. This is a list collection of<br />

%ZEN.Auxiliary.gridColumn objects. Each provided in the original definition<br />

in XData Contents becomes a member of the columns collection, associated with its ordinal position<br />

in the : 1, 2, 3, etc.<br />

214 <strong>Using</strong> <strong>Zen</strong>


Spreadsheet<br />

12.9.5 Attributes<br />

When you place a element within an XData Contents block, you can assign it the following<br />

attributes. When working with the programmatically, these attributes are available as<br />

properties of the dynaGrid object.<br />

Attribute<br />

Control component<br />

attributes<br />

controllerId<br />

currColumn<br />

currPage<br />

currRow<br />

gridLabel<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong><br />

control. However, unlike most other controls it does not have a<br />

single value.<br />

If this is associated with a data controller, the<br />

controllerId attribute identifies the controller that provides the data<br />

for this .The controllerId value must match the id value<br />

provided for that . See Model View Controller.<br />

The 1–based column number of the currently selected cell in the<br />

grid. The default (until the user makes selections) is 1.<br />

The 1–based page number of the data currently displayed in the<br />

grid. If the data set associated with this grid contains<br />

three–dimensional data, currPage indicates which page (along<br />

the third dimension) is currently displayed. The default is 1.<br />

The 1–based row number of the currently selected cell in the grid.<br />

The default (until the user makes selections) is 1.<br />

Caption to display in the upper-left corner cell.<br />

Although you enter ordinary text for this attribute, it has the<br />

underlying data type %ZEN.Datatype.caption. This makes it easy to<br />

localize its text into other languages. See <strong>Zen</strong> Localization.<br />

<strong>Using</strong> <strong>Zen</strong> 215


<strong>Zen</strong> Controls<br />

Attribute<br />

onchangecell<br />

Description<br />

(Optional) Client-side JavaScript expression that is executed<br />

whenever the user changes the contents of a cell. Generally this<br />

expression invokes a client-side JavaScript method defined in the<br />

page class. This method becomes the “onchangecell event handler”<br />

for the .<br />

If you omit the onchangecell attribute, the default behavior is to<br />

assign the user-entered value to the cell.<br />

When providing a value for an event handler attribute such as<br />

onchangecell, use double quotes to enclose the value and single<br />

quotes (if needed) within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

onclickcolumn<br />

onclickrow<br />

OnCreateDataSet<br />

ondrawcell<br />

oneditcell<br />

(Optional) Client-side JavaScript expression that is executed<br />

whenever the user clicks on a column header cell (at the top of a<br />

column).<br />

(Optional) Client-side JavaScript expression that is executed<br />

whenever the user clicks on a row header cell (at the left of a row).<br />

As described in the topic Data Set, the<br />

OnCreateDataSet value is the name of a server-side callback<br />

method that provides the data set associated with this .<br />

(Optional) Client-side JavaScript expression that is executed when<br />

the is about to draw a cell. If this event handler returns<br />

a value, this value is used as DHTML to render the cell contents.<br />

This convention provides a way to display custom cell formatting<br />

within a .<br />

(Optional) Client-side JavaScript expression that is executed when<br />

the is ready to accept user input in one of its cells. If<br />

the oneditcell event handler returns a value, this value is used as<br />

DHTML to render the editor used for the cell. oneditcell provides<br />

a way to display a custom cell editor within a . The<br />

default behavior is to place an HTML input control over that region<br />

of the grid to permit the user to enter data. There is no need to<br />

override this default, but you may.<br />

216 <strong>Using</strong> <strong>Zen</strong>


Spreadsheet<br />

Attribute<br />

onnotifyView<br />

Description<br />

This attribute applies if the is associated with a data<br />

controller. The onnotifyView value is a client-side JavaScript<br />

expression that is executed each time the data controller connected<br />

to this raises an event. Generally this<br />

expression invokes a client-side JavaScript method defined in the<br />

page class.This method becomes the “onnotifyView event handler”<br />

for the . See Model View Controller.<br />

When providing a value for this attribute, use double quotes to<br />

enclose the value and single quotes (if needed) within the<br />

JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

rowLabelWidth<br />

showColumnLabels<br />

showRowLabels<br />

HTML width value, such as 3 or 0.3in or 3%. rowLabelWidth<br />

applies to the column of row labels. The default width is 100.<br />

If true, column labels are displayed in a row along the top of the<br />

grid. The default is true.<br />

showColumnLabels has the underlying data type<br />

%ZEN.Datatype.boolean. It has the value "true" or "false" in XData<br />

Contents, 1 or 0 in server-side code, true or false in client-side<br />

code. See Datatype Classes.<br />

If true, row labels are displayed in a column along the left side of<br />

the grid. The default is true.<br />

showRowLabels has the underlying data type<br />

%ZEN.Datatype.boolean. It has the value "true" or "false" in XData<br />

Contents, 1 or 0 in server-side code, true or false in client-side<br />

code. See Datatype Classes.<br />

<strong>Using</strong> <strong>Zen</strong> 217


13<br />

Model View Controller<br />

To simplify the flow of data from a data source to a <strong>Zen</strong> page, <strong>Zen</strong> provides a set of classes that let<br />

you define a data model (the model) and connect it to a set of <strong>Zen</strong> components (the view) via an<br />

intermediate object (the controller). The name for this mechanism is Model View Controller, or<br />

MVC. The following are some typical uses of MVC:<br />

• Create a form that displays a set of properties, loaded from a persistent object within the database.<br />

The form automatically displays controls appropriate to the data type of each property.<br />

• Display a chart based on values within a form. The chart automatically updates its display whenever<br />

the user submits any changes to the form.<br />

• Display meters representing values calculated on the server. When the page is refreshed, these<br />

meters automatically update themselves with current values from the server.<br />

13.1 Architecture<br />

The following figure shows the three parts of the MVC architecture — model, view, and controller<br />

— and indicates where these objects execute their code. The controller and its associated views are<br />

<strong>Zen</strong> components, placed on the <strong>Zen</strong> page. The controller component is hidden from view, but view<br />

components are user-visible. The view components display data values, which they obtain by<br />

requesting them from the controller. The controller resides on the client, but has the ability to execute<br />

code on the server. The model resides entirely on the server. It draws its data values from a source on<br />

the server and can respond to requests for data from the controller.<br />

<strong>Using</strong> <strong>Zen</strong> 219


Model View Controller<br />

Model View Controller Architecture<br />

13.1.1 Data Model<br />

A data model is any subclass of %ZEN.DataModel.DataModel. A data model can:<br />

1. Retrieve data values from one or more sources, such as:<br />

• A persistent Caché object<br />

• An external database (ODBC or JDBC) via the Caché SQL Gateway<br />

• A Caché global<br />

• An Ensemble business service<br />

2. Place these values into its own properties.<br />

3. Make these properties available to be consumed by a data controller.<br />

There are two variations on a data model class. Typically you will choose one of these as your parent<br />

class when you create a new data model. The variations are closely related, but serve different purposes.<br />

The available data model subclasses are %ZEN.DataModel.ObjectDataModel and<br />

%ZEN.DataModel.Adaptor, as shown in the following figure.<br />

220 <strong>Using</strong> <strong>Zen</strong>


Architecture<br />

Data Model Classes<br />

13.1.1.1 %ZEN.DataModel.ObjectDataModel<br />

A subclass of %ZEN.DataModel.ObjectDataModel is called an object data model. It defines one or<br />

more properties that a data controller component can consume. Each of these properties is correlated<br />

with a value from the data source class. Not every value in the data source needs to be exposed in the<br />

model. This convention allows you to expose in the data model only those values that you wish to.<br />

An example of this might be a patient record, which contains confidential information that not every<br />

application should expose. Keep in mind that when you use this option, the developer of the object<br />

data model class is responsible for implementing methods to load values from a source into data model<br />

properties, store values back to a source, and validate values. This is in contrast to the adaptor data<br />

model, where <strong>Zen</strong> takes care of these details. However, this is not such a difficult procedure, as the<br />

next major topic, Building a Form, will explain.<br />

<strong>Using</strong> <strong>Zen</strong> 221


Model View Controller<br />

For examples, use Studio to view the classes ZENMVC.FormDataModel and ZENMVC.FormDataModel2<br />

in the SAMPLES namespace.<br />

13.1.1.2 %ZEN.DataModel.Adaptor<br />

There are many times where it is convenient to use a persistent object as a data model object. To make<br />

this easy to accomplish, <strong>Zen</strong> provides the %ZEN.DataModel.Adaptor interface. Adding this an additional<br />

superclass to a persistent class will make it possible to use the persistent class as a data model. This<br />

data model makes available to a data controller any and all properties that it contains. This option is<br />

useful when you want to expose every property in an existing class.<br />

An example of this might be a class that you are using in an inventory or parts control application,<br />

wherein each product might be described by a class with a large number of properties. If you want to<br />

place all of these properties onto a form automatically without writing another class, you can simply<br />

cause the product class to extend %ZEN.DataModel.Adaptor. Following that, <strong>Zen</strong> simply generates the<br />

form for you, as later topics will explain.<br />

The drawback of this choice is that your data and form are very closely linked. If you want some<br />

flexibility, you should subclass the object data model class and implement the internal interface. This<br />

is the classic trade-off of convenience versus flexibility.<br />

For examples, use Studio to view the classes ZENMVC.Address and ZENMVC.Person in the SAMPLES<br />

namespace.<br />

13.1.2 Data Controller<br />

A data controller is any subclass of %ZEN.Auxiliary.dataController. Through class inheritance, every<br />

data controller is also a <strong>Zen</strong> component, as the following figure shows. This convention permits you<br />

to place a data controller on a <strong>Zen</strong> page.<br />

222 <strong>Using</strong> <strong>Zen</strong>


Architecture<br />

Data Controller and Data View Classes<br />

A data controller manages the communication between a data model and a data view. The <br />

component appears in the page description along with other components, but it is not visible<br />

on the output page. Its role is as an intermediary between a data model and one or more data views.<br />

13.1.2.1 Data Controller Attributes<br />

When you place a within a <strong>Zen</strong> , you can assign it the following attributes.<br />

Attribute<br />

<strong>Zen</strong> component<br />

attributes<br />

defaultSeries<br />

modelClass<br />

Description<br />

A has the same general-purpose attributes as any<br />

<strong>Zen</strong> component. The chapter <strong>Zen</strong> Style describes them. The id<br />

attribute is required for . name and condition may<br />

also apply. A is not visible, so visual style attributes<br />

do not apply.<br />

Optional. If a data model has multiple data series, defaultSeries is<br />

a 1-based number that specifies which series should be used to<br />

provide values to data views that can only display values from one<br />

data series (such as a form). The default is 1.<br />

Package and class name of the data model class that provides data<br />

for this . Changing the modelClass value causes<br />

the controller to abandon the previous model and load data from the<br />

new model.<br />

The modelClass value can be a literal string, or it can contain a <strong>Zen</strong><br />

#()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

<strong>Using</strong> <strong>Zen</strong> 223


Model View Controller<br />

Attribute<br />

modelId<br />

oncreate<br />

Description<br />

String that identifies a specific instance of a data model object. The<br />

form and possible values of the modelId string are determined by<br />

the developer of the data model class. Changing the modelId value<br />

causes the controller to load a new record, and to update its associated<br />

views.<br />

The modelId value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

Client-side JavaScript expression that runs each time the<br />

createNewObject method is called. Generally this expression<br />

invokes a client-side JavaScript method. This method becomes the<br />

“oncreate event handler” for the .<br />

When providing a value for an event handler attribute such as<br />

oncreate, use double quotes to enclose the value and single quotes<br />

(if needed) within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

ondelete<br />

onerror<br />

onnotifyController<br />

onsave<br />

Client-side JavaScript expression that runs each time the deleteId<br />

method is called. The parameter id is passed to the event handler<br />

and contains the modelId of the deleted object.<br />

Client-side JavaScript expression that runs each time the data controller<br />

attempts to open an instance of a data model object and<br />

encounters an error.<br />

When you work with a %ZEN.Auxiliary.dataController programmatically,<br />

you can obtain the most recent error message reported by the data<br />

model object associated with this data controller, by examining the<br />

modelError property of the dataController object. This property is not<br />

available as an XML attribute when adding the to<br />

the <strong>Zen</strong> page.<br />

Client-side JavaScript expression that runs each time a data view<br />

connected to this data controller raises an event.<br />

Client-side JavaScript expression that runs each time the save<br />

method is called. The parameter id is passed to the event handler<br />

and contains the current modelId.<br />

224 <strong>Using</strong> <strong>Zen</strong>


Architecture<br />

Attribute<br />

autoRefresh<br />

Description<br />

Setting autoRefresh to a non-zero value turns on automatic refresh<br />

mode for this data controller. In this mode, the data controller reloads<br />

its data from the server at the periodic interval specified by<br />

autoRefresh (in milliseconds). autoRefresh is provided as a<br />

convenience for data controller used to drive meters or charts; it is<br />

of limited use for forms. Setting autoRefresh to 0 disables automatic<br />

refresh mode.<br />

13.1.2.2 Data Controller Changes<br />

The following data controller attributes can be changed to affects what is seen on screen:<br />

• modelClass — Cause the data controller to look at a different data model<br />

• modelId — Cause the data controller to look at a different data record within the same model<br />

• defaultSeries — Cause the data controller to look at a different data series within the same data<br />

record and model<br />

The SAMPLES namespace class ZENMVC.MVCForm allows you to experience changes in these data<br />

controller attributes. Try entering the following URI in the browser:<br />

http://localhost:57772/csp/samples/ZENMVC.MVCForm.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché. To change the model<br />

ID, click the Previous and Next buttons. to change the model class, click the Change Model button.<br />

You can use Studio to view the class code.<br />

13.1.3 Data View<br />

A data view is any <strong>Zen</strong> component that implements the %ZEN.Component.dataView interface. As<br />

shown in the previous figure, this includes:<br />

• <br />

• All forms<br />

• All charts<br />

• All meters<br />

A data view component connects to its associated data controller at runtime, and uses it to get and set<br />

values from the associated data model. A data view points to its data controller; more than one data<br />

view can point to the same data controller.<br />

<strong>Using</strong> <strong>Zen</strong> 225


Model View Controller<br />

13.1.3.1 Data View Attributes<br />

Data view components support the usual <strong>Zen</strong> component attributes, plus any specialized attributes that<br />

are typical of the specific type of component. Additionally, all data view components support the following<br />

attributes, which relate specifically to the component’s role as a data view.<br />

Attribute<br />

controllerId<br />

dataBinding<br />

Description<br />

Identifies the data controller for this data view (). The controllerId value<br />

must match the id value provided for that component.<br />

Identifies the data model property that is bound to this component. This<br />

property provides the value that the component displays:<br />

• If the dataBinding value is a simple property name, this is assumed<br />

to be a property within the data model class identified by the modelClass attribute.<br />

• Alternatively, dataBinding can provide a full package, class, and<br />

property name.<br />

dataBinding is suitable only for components that display a single value<br />

(meters or controls). Each meter on a <strong>Zen</strong> page must supply a controllerId<br />

and a dataBinding. Controls do not support the data view interface, so<br />

cannot supply a controllerId, but if the form that contains the controls<br />

has an associated data controller, each control within the form can<br />

supply a dataBinding attribute that identifies which property it displays.<br />

onnotifyView<br />

Client-side JavaScript expression that is executed each time the data<br />

controller associated with this data view raises an event. Generally this<br />

expression invokes a client-side JavaScript method defined in the page<br />

class. This method becomes the “onnotifyView event handler” for the<br />

data view component.<br />

When providing a value for this attribute, use double quotes to enclose<br />

the value and single quotes (if needed) within the JavaScript expression.<br />

For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

226 <strong>Using</strong> <strong>Zen</strong>


Architecture<br />

13.1.3.2 The Controller Object<br />

When you work with a data view component programmatically, you can obtain a reference to the<br />

associated %ZEN.Auxiliary.dataController object via the following properties of the<br />

%ZEN.Component.dataView interface:<br />

• controller — Use in JavaScript code that runs on the client side<br />

• %controller — Use in ObjectScript or Basic code that runs on the server side<br />

13.1.3.3 Multiple Data Views<br />

Whenever a user modifies a value within one of the controls that is bound to a data controller, the data<br />

controller is notified. It is common for data views to share a controller; for example, different types<br />

of chart on the same page could share the same data controller to display different visualizations of<br />

the same data, as in the following figure. If there are multiple data view components connected to the<br />

same data controller, they are all notified of any change to a bound control.<br />

For examples of shared data controllers, use Studio to view the classes ZENMVC.MVCChart and<br />

ZENMVC.MVCMeters. The class ZENMVC.MVCMeters uses the same data controller to provide values<br />

for a and several meters. The class ZENMVC.MVCChart provides a and three<br />

charts that all use the same data controller. Try entering the following URIs in the browser:<br />

http://localhost:57772/csp/samples/ZENMVC.MVCChart.cls<br />

http://localhost:57772/csp/samples/ZENMVC.MVCMeters.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché.<br />

When you change a value in one of these pages by editing it in the and pressing Enter,<br />

this change affects the corresponding value in all the charts (or meters) on the same page, because all<br />

of them share the same data controller. In the following figure, the user has just modified the Trucks<br />

field in the for ZENMVC.MVCChart.<br />

<strong>Using</strong> <strong>Zen</strong> 227


Model View Controller<br />

13.2 Constructing a Model<br />

This topic provides the first in a series of exercises that show how to use the Model View Controller<br />

to create a form. The topics are:<br />

• Constructing a Model<br />

• Binding a to an Object Data Model<br />

• Adding Behavior to the <br />

• with an Object Data Model<br />

• with an Adaptor Data Model<br />

If you have a new Caché installation, before you begin these exercises you must first generate data<br />

records for the SAMPLES namespace. You only need to do this once per Caché installation. Enter the<br />

following URI in the browser:<br />

http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché.<br />

13.2.1 Step 1:Type of Model<br />

There are two basic choices when generating a form using the Model View Controller:<br />

• %ZEN.DataModel.ObjectDataModel or %ZEN.DataModel.Adaptor<br />

An object data model takes more work to code. An object data model gives you explicit control<br />

over which properties end up in the model, so it makes more sense for cases when you want to<br />

shield certain properties from display or when you want to display charts, which require very fine<br />

data control. The choice of adaptor data model is simple and convenient, but it imposes a burden<br />

on the original persistent object, in that you must change its class code to allow it to become an<br />

adaptor data model.<br />

• or <br />

A is a good choice for the key forms that are critical to the success of your application.<br />

A requires more work to encode, but provides as fine a level of control as you need to<br />

perfect the results. A provides automatic results and automatically updates its layout<br />

if you change the underlying data model. This is useful to generate forms for large volumes of<br />

detailed information such as system administration, inventory, or maintenance requests.<br />

For this exercise we choose an object data model and a .<br />

228 <strong>Using</strong> <strong>Zen</strong>


Constructing a Model<br />

13.2.2 Step 2: Object Data Model<br />

Suppose a persistent object called Patient contains a patient record. This object may have hundreds of<br />

properties. Suppose you want to create a simple page that only displays demographic information, in<br />

this case the patient’s name and city of residence. This is a clear case for using<br />

%ZEN.DataModel.ObjectDataModel.<br />

First, define an object data model class called PatientModel that knows how to load and store properties<br />

from the Patient object:<br />

1. Start Caché Studio.<br />

2. Choose File > Change Namespace or F4.<br />

3. Choose the SAMPLES namespace.<br />

4.<br />

Choose File > New or Ctrl-N or the<br />

5. Click the General tab.<br />

6. Click the Caché Class Definition icon.<br />

icon.<br />

7. Click OK.<br />

8. For Package Name enter:<br />

MyApp<br />

9. In the Class Name field, type:<br />

PatientModel<br />

10. Click Next.<br />

11. Choose Extends<br />

12. Click Next and enter (or browse to) this class name:<br />

%ZEN.DataModel.ObjectDataModel<br />

13. Click Finish.<br />

Studio creates and displays a skeletal object data model class:<br />

Class MyApp.PatientModel Extends %ZEN.DataModel.ObjectDataModel<br />

{<br />

}<br />

14. Add properties and methods to complete the class as shown in the following code example. This<br />

example defines two properties for the data model (Name and City). It also overrides several of<br />

the server-side methods in the %ZEN.DataModel.ObjectDataModel interface. For documentation<br />

of these methods, refer to the topic Object Data Model Callback Methods, later in this chapter.<br />

<strong>Using</strong> <strong>Zen</strong> 229


Model View Controller<br />

Class MyApp.PatientModel Extends %ZEN.DataModel.ObjectDataModel<br />

{<br />

Property Name As %String;<br />

Property City As %String;<br />

/// Load an instance of a new (unsaved) source object for this DataModel.<br />

Method %OnNewSource(Output pSC As %Status = {$$$OK}) As %RegisteredObject<br />

{<br />

Quit ##class(ZENDemo.Data.Patient).%New()<br />

}<br />

/// Load an instance of the source object for this DataModel.<br />

Method %OnSaveSource(pSource As ZENDemo.Data.Patient) As %Status<br />

{<br />

Set tSC=pSource.%Save()<br />

If $$$ISOK(tSC) Set ..%id=pSource.%Id()<br />

Quit tSC<br />

}<br />

/// Load an instance of the source object for this DataModel.<br />

Method %OnOpenSource(pID As %String, pConcurrency As %Integer = -1,<br />

Output pSC As %Status = {$$$OK}) As %RegisteredObject<br />

{<br />

Quit ##class(ZENDemo.Data.Patient).%OpenId(pID,pConcurrency,.pSC)<br />

}<br />

/// Delete instance of associated source object.<br />

ClassMethod %OnDeleteSource(pID As %String) As %Status<br />

{<br />

Quit ##class(ZENDemo.Data.Patient).%DeleteId(pID)<br />

}<br />

}<br />

/// Do the actual work of loading values from the source object.<br />

Method %OnLoadModel(pSource As ZENDemo.Data.Patient) As %Status<br />

{<br />

Set ..Name = pSource.Name<br />

}<br />

Set ..City = pSource.Home.City<br />

Quit $$$OK<br />

/// Do the actual work of storing values into the source object.<br />

Method %OnStoreModel(pSource As ZENDemo.Data.Patient) As %Status<br />

{<br />

Set pSource.Name = ..Name<br />

Set pSource.Home.City = ..City<br />

Quit $$$OK<br />

}<br />

15.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

icon.<br />

13.3 Binding a to an Object Data Model<br />

This exercise creates a data controller based on the object data model from the previous exercise. It<br />

then binds a form to this data controller.<br />

230 <strong>Using</strong> <strong>Zen</strong>


Binding a to an Object Data Model<br />

13.3.1 Step 1: Data Controller<br />

If you do not already have a simple <strong>Zen</strong> application and page class available from previous exercises,<br />

create them now using instructions from the <strong>Zen</strong> Tutorial chapter:<br />

• Creating a <strong>Zen</strong> Application — Create the class MyApp.MyNewApp.<br />

• Creating a <strong>Zen</strong> Page — Create the class MyApp.MyNewPage. You only need to complete the steps<br />

in the first section, Step 1: New Page Wizard.<br />

Now place a data controller component on the <strong>Zen</strong> page by adding a element in the<br />

MyApp.MyNewPage class XData Contents block, inside the container, as follows:<br />

<br />

Where:<br />

• id is the unique identifier of the data controller on the <strong>Zen</strong> page. A data view (such as a form) will<br />

specify its data controller using this id.<br />

• modelClass is package and class name of the data model class. The previous exercise created the<br />

class MyApp.PatientModel which is an object data model that represents objects of the<br />

ZENDemo.Data.Patient class.<br />

• modelId is a number that identifies the record to initially load from the data source. In this case,<br />

it is the identifier of a specific ZENDemo.Data.Patient object.<br />

Note:<br />

The component is not visible on the page.<br />

13.3.2 Step 2: Data View<br />

Now create a form and connect it to the data controller, as follows:<br />

1. Place a component inside the container.<br />

Bind the form to the data controller from the previous topic by setting the controllerId<br />

to match the id value. For example:<br />

<br />

<br />

The id attribute does not affect the binding but becomes useful in a future step, when we will save<br />

the form.<br />

2. Within the add two controls.<br />

<strong>Using</strong> <strong>Zen</strong> 231


Model View Controller<br />

Bind each control to a property of the data model by providing a dataBinding attribute that<br />

identifies a property within the modelClass of the . Also provide a label for each<br />

control. For example:<br />

<br />

<br />

<br />

<br />

The label attribute does not have any purpose relative to the Model View Controller, but it is<br />

necessary if we want our controls to have a meaningful labels on the <strong>Zen</strong> page.<br />

13.3.3 Step 3: Initial Results<br />

View your initial results as follows:<br />

1. Open your <strong>Zen</strong> page class in Studio.<br />

2.<br />

3.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the<br />

icon.<br />

icon.<br />

The data controller component creates a MyApp.PatientModel object on the server, and asks it to<br />

load data from data source record number 1 (identified by the modelId attribute)<br />

into its own properties. The data controller places these data values into the appropriate controls<br />

within the form. The dataBinding attribute for each control identifies which property provides the<br />

value for that control, Name or City.<br />

The following figure shows our form with the current values from record 1.<br />

13.3.4 Step 4: Saving the Form<br />

Suppose you want the user to be able to edit the values in this form, and to save changes. To save the<br />

values in a form associated with a data controller, your application must call the form’s save method.<br />

Typically you would enable this as follows:<br />

1. Add a client-side method to the page class as follows:<br />

232 <strong>Using</strong> <strong>Zen</strong>


Method save() [ Language = javascript ]<br />

{<br />

var form = zenPage.getComponentById('MyForm');<br />

Binding a to an Object Data Model<br />

}<br />

form.save();<br />

Now you can see why it was important to define an id for our . The method<br />

getComponentById needs this id to get a reference for the form so that we can call its save<br />

method.<br />

2. Add to your page a that calls this method to save the form.<br />

The entire definition now looks something like this:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

3. Try editing the data and clicking Save.<br />

Each time the user clicks the Save button, the form save method calls back to the server and saves the<br />

data by calling the appropriate methods of the data model class. During this process, the form ask the<br />

data controller to assist with data validation of the various properties. The source of this validation<br />

logic is the data model class.<br />

The data controller also has a save method we can use. There is a difference between saving the form<br />

and saving the controller. Calling the save method of the form triggers the form validation logic, after<br />

which the form instructs the controller to save data by calling the appropriate methods of the data<br />

model class. Saving the controller skips form validation.<br />

You can try out basic form validation in step 3 of this example as follows: If you empty the Patient<br />

Name field entirely and click Save, a validation error occurs. This is because the Patient property is<br />

marked as Required in the ZENDemo.Data.Patient class that serves as our data source. However, if<br />

you change the Patient Name or Patient City to any non-empty value, the form saves correctly. It will<br />

be easier to prove this to yourself once you have extended the form to allow you to easily view more<br />

than one data record. Then you can switch back and forth between records to see that they in fact<br />

contain your changes.<br />

Note:<br />

For further validation examples, try using and viewing the <strong>Zen</strong> page class ZENMVC.MVCForm<br />

in the SAMPLES namespace. Try entering the following URI in the browser:<br />

http://localhost:57772/csp/samples/ZENMVC.MVCForm.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché. Edit values<br />

in one of the forms shown on the page, and click a Submit button. You can use Studio to<br />

view the class code.<br />

<strong>Using</strong> <strong>Zen</strong> 233


Model View Controller<br />

Rather than wait for server-side validation, we can add client-side validation to the data model class<br />

by defining a property-specific IsValidJS method. This is a JavaScript class method that uses the<br />

naming convention propertyIsValidJS and returns an error message if the value of the given property<br />

is invalid or '' (an empty string) if the value is OK. This method can be defined within the data model<br />

class, or you can define a datatype class that defines a propertyIsValidJS method.<br />

Adding the following method to the MyApp.PatientModel class causes the data controller to automatically<br />

apply this validation to the City property on the client each time its save method is called:<br />

ClassMethod CityIsValidJS(value) [Language = javascript]<br />

{<br />

return ('Boston' == value) 'Invalid City Name' : '';<br />

}<br />

13.4 Adding Behavior to the <br />

The %ZEN.Auxiliary.dataController class offers several useful methods. Suppose you want to enhance<br />

your page from the previous exercise so that it can open new records, create new records, delete existent<br />

records, or reset the current record to a particular model ID. This topic explain how to accomplish<br />

these tasks using dataController methods such as getModelId and setModelId.<br />

13.4.1 Step 1: Opening a New Record<br />

When you ask the browser to display the page you have been building during these exercises, it always<br />

displays the same data record. This is because you have configured the modelId property of your<br />

element with the value of 1. You can see what happens if you change this property<br />

to other values, such as 2, 3, or 4, up to 1000.<br />

However, you must remember that these values represent real ID values of existing instances of the<br />

ZENDemo.Data.Patient class. These instances exist because all of the classes in ZENDemo.Data are<br />

populated automatically when you first run the <strong>Zen</strong> Demo as described in the first chapter, Introducing<br />

<strong>Zen</strong>.<br />

Suppose you want to give the user the option of choosing which record to view. There are several<br />

options, including:<br />

• Add a text field that allows the user to enter an ID<br />

• Add a combo box that allows the user to choose the record by one of its properties, such as a<br />

patient name<br />

• Add a table that allows the user to click on a patient name and see the details on a form below<br />

It does not matter which option you choose for user input. The key task is for your page to be able to<br />

tell the data controller to load the record. You can accomplish this as follows:<br />

234 <strong>Using</strong> <strong>Zen</strong>


Adding Behavior to the <br />

1. Open your <strong>Zen</strong> page class in Studio.<br />

2. Add a new text field to the :<br />

<br />

<br />

<br />

<br />

<br />

3. Add a corresponding client-side method:<br />

Method loadRecord(id) [ Language = javascript ]<br />

{<br />

var controller = zenPage.getComponentById('patientData');<br />

}<br />

controller.setModelId(id);<br />

The onblur event calls a client-side method loadRecord that first gets a pointer to the data controller<br />

using its id value "patientData", then uses whatever the user has entered in the field as a<br />

modelId to load the desired record from the data model. To actually load the record, loadRecord<br />

uses the data controller method setModelId.<br />

Also observe that this example binds the ID field to the %id property of the data model, so that<br />

this field will always show you the ID of the current record. This is not necessary for setModelId<br />

to work, but it will be very useful in the next topic.<br />

4.<br />

5.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the icon.<br />

The following figure shows the form.<br />

icon.<br />

6. Try the onblur functionality as follows:<br />

• Enter 2 (or any other number) in the ID field.<br />

<strong>Using</strong> <strong>Zen</strong> 235


Model View Controller<br />

• Press the Tab key to move out of the ID field.<br />

• The alternate record should display.<br />

7. In Binding a to an Object Data Model, Step 4: Saving the Form, you added Save functionality<br />

without the ability to easily test it. Try it now, as follows:<br />

• Note the number of the current record.<br />

• Make a significant change to the Name or City field.<br />

• Click Save.<br />

• Enter a different number in the ID field.<br />

• Press the Tab key to move out of the ID field.<br />

• The alternate record should display.<br />

• Enter the number for the record that you saved in the ID field.<br />

• Press the Tab key to move out of the ID field.<br />

• Your saved changes should be visible on the form.<br />

13.4.2 Step 2: Creating and Deleting Records<br />

Creating and deleting records are also simple tasks. Modify your page to add the necessary buttons<br />

and client side code as follows.<br />

1. Open your <strong>Zen</strong> page class in Studio.<br />

2. After the and before the closing , replace the single Save button with the following<br />

:<br />

<br />

<br />

<br />

<br />

<br />

<br />

These statements add the buttons to an so that they will appear on the screen in a row.<br />

Each button defines its onclick method as a different client-side method.<br />

3. Add the corresponding new client-side methods to the page class:<br />

Method newRecord() [ Language = javascript ]<br />

{<br />

var controller = zenPage.getComponentById('patientData');<br />

}<br />

controller.createNewObject();<br />

And:<br />

236 <strong>Using</strong> <strong>Zen</strong>


Method updateRecord() [ Language = javascript ]<br />

{<br />

var controller = zenPage.getComponentById('patientData');<br />

Adding Behavior to the <br />

}<br />

controller.update();<br />

And:<br />

Method deleteRecord() [ Language = javascript ]<br />

{<br />

var controller = zenPage.getComponentById('patientData');<br />

controller.deleteId(controller.getModelId());<br />

controller.createNewObject();<br />

}<br />

Each of these methods uses a different dataController method to achieve its purposes.<br />

4.<br />

5.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the icon.<br />

The following figure shows the form.<br />

icon.<br />

13.4.2.1 New<br />

Suppose the user clicks New. Calling createNewObject immediately creates a new empty model. In<br />

the browser, every time the user clicks New the form is emptied. After that, if the user completes the<br />

empty form and clicks Save, this invokes the form’s save method. This (eventually) leads to a call to<br />

the data model’s %OnSaveSource method on the server.<br />

In Binding a to an Object Data Model, Step 4: Saving the Form, you added Save functionality<br />

by causing the %OnSaveSource method to set the %id property of the model to the ID of the saved<br />

object, as follows:<br />

<strong>Using</strong> <strong>Zen</strong> 237


Model View Controller<br />

Method %OnSaveSource(pSource As ZENDemo.Data.Patient) As %Status<br />

{<br />

Set tSC=pSource.%Save()<br />

If $$$ISOK(tSC) Set ..%id=pSource.%Id()<br />

Quit tSC<br />

}<br />

As a result, every time the user clicks New, enters values, then clicks Save, the form shows the newlyassigned<br />

ID to the user (thanks to the dataBinding on that field). Of course, this only works if the data<br />

entered in the form passes validation. Name is a required field, so if no Name is entered, the record is<br />

not saved.<br />

13.4.2.2 Delete<br />

Suppose the user clicks Delete. The data controller’s deleteId method expects to recieve the ID for<br />

the record to be deleted. Therefore, when the user clicks Delete, the page uses the data controller’s<br />

getModelId method to determine the ID of the record the user is currently viewing. It passes this ID<br />

on to deleteId. This (eventually) leads to a call to the data model’s %OnDeleteSource method on the<br />

server. The source object is deleted, and since there will be no source object anymore, the page calls<br />

the data controller’s createNewObject method to empty the form and prepare it for new input.<br />

Important:<br />

If, while using this exercise, you delete a record with a specific ID, this object no<br />

longer exists. You cannot view or create a record with this ID again.<br />

13.4.2.3 Update<br />

Before clicking Update, the user must enter an ID number (between 1 and 1000) in the ID field. The<br />

page updates the form fields with data from that record. This fails only if you have previously deleted<br />

a record with that ID.<br />

13.5 with an Object Data Model<br />

This topic explains how to use with a data controller. In this case the data model is an<br />

object data model.<br />

13.5.1 Step 1: is Easy<br />

You may create your first very easily as follows:<br />

1. Create a new <strong>Zen</strong> page class. Use the steps in Creating a <strong>Zen</strong> Page, Step 1: New Page Wizard.<br />

Call your new class anything you like, but keep it in the MyApp package. Be careful not to overwrite<br />

your previous work.<br />

2. In XData Contents, place a and inside :<br />

238 <strong>Using</strong> <strong>Zen</strong>


<br />

<br />

<br />

with an Object Data Model<br />

3.<br />

4.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the<br />

icon.<br />

icon.<br />

The form displays two fields that contain the current Name and City values for the record whose<br />

modelId you entered in the statement. Perhaps you have changed these values,<br />

or deleted this record, during previous exercises. Whatever data is now available for that modelId<br />

displays.<br />

The label for each control is determined by the corresponding property name in MyApp.PatientModel.<br />

These labels are different from the text you assigned to the caption attribute when you used <br />

and components to lay out the form. In all other respects, this display is identical to the<br />

display you first saw in Building a Form, Step 3: Initial Results. Later steps show how to set specific<br />

labels for the controls in a .<br />

13.5.2 Step 2: Converting to <br />

Now you are ready to recreate the example from previous exercises as a . To do<br />

this, you will need to rewrite your MyApp.MyNewPage XData Contents block so that it looks like this:<br />

<strong>Using</strong> <strong>Zen</strong> 239


Model View Controller<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

That is:<br />

1. In Studio, return to your existing sample page, MyApp.MyNewPage.<br />

2. Remove or comment out this , which specifies each control individually:<br />

<br />

<br />

<br />

<br />

<br />

3. Add this , which relies on the data controller to supply it with any control definitions<br />

that can be generated based on properties in the data model:<br />

<br />

<br />

<br />

<br />

Where:<br />

• controllerId identifies the data controller.<br />

• defaultGroupId identifies the group, on the form, that will contain the controls generated by<br />

that data controller.<br />

• defaultGroupId is optional; but if it appears in the then somewhere inside the<br />

, you must specify a group with an id that matches the defaultGroupId, in this<br />

case a .<br />

240 <strong>Using</strong> <strong>Zen</strong>


with an Object Data Model<br />

• If you want controls to appear on the form that do not depend on the data controller, such as<br />

the control whose value is based on the %id variable, you must place them explicitly, as<br />

shown.<br />

4.<br />

5.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

Choose View > Web Page or the icon.<br />

The following displays:<br />

icon.<br />

6. You may assign specific labels to the generated controls on the as follows:<br />

• In Studio, open the object data model class, MyApp.PatientModel.<br />

• Edit the properties to add the ZENLABEL parameter to each of them:<br />

Property Name As %String(ZENLABEL = "Patient Name");<br />

And:<br />

Property City As %String(ZENLABEL = "Patient City");<br />

•<br />

Choose Build > Compile or Ctrl-F7 or the<br />

icon to compile the data model.<br />

7. Refresh your <strong>Zen</strong> page MyApp.MyNewPage in the browser.<br />

Your and now produce identical results.<br />

13.5.3 Step 3: Automatic Control Selection<br />

When you use instead of , it is no longer necessary to add data view components<br />

(controls) to the form, item by item, as in the first example of building a form. This information is now<br />

extracted automatically from the data model. determines which type of control to assign<br />

to each property in the model based on its data type.<br />

<strong>Using</strong> <strong>Zen</strong> 241


Model View Controller<br />

The following exercise demonstrates this by adapting your existing page class to use a different data<br />

model. When you complete the exercise and display the page, a new form will appear whose controls<br />

are clearly different from those we previously used:<br />

1. Return to Studio in the SAMPLES namespace.<br />

2. Choose Tools > Copy Class.<br />

3. The Class Copy dialog displays. Enter:<br />

• Copy Class — MyApp.PatientModel<br />

• To — MyApp.EmployeeModel<br />

• Check the Replace Instances of Class Name box.<br />

• Click OK.<br />

The new class definition for MyApp.EmployeeModel displays in Studio.<br />

4. Edit MyApp.EmployeeModel so that it has the following three properties only:<br />

Property Name As %String;<br />

Property Salary As %Numeric;<br />

Property Active As %Boolean;<br />

5. Edit the methods inside MyApp.EmployeeModel to work with the new properties:<br />

Method %OnLoadModel(pSource As ZENDemo.Data.Employee) As %Status<br />

{<br />

Set ..Name = pSource.Name<br />

}<br />

Set ..Salary = pSource.Salary<br />

Set ..Active = pSource.Active<br />

Quit $$$OK<br />

And:<br />

Method %OnStoreModel(pSource As ZENDemo.Data.Employee) As %Status<br />

{<br />

Set pSource.Name = ..Name<br />

}<br />

Set pSource.Salary = ..Salary<br />

Set pSource.Active = ..Active<br />

Quit $$$OK<br />

6.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

icon.<br />

7. Choose Tools > Copy Class.<br />

8. The Class Copy dialog displays. Enter:<br />

• Copy Class — MyApp.MyNewPage<br />

• To — MyApp.MyOtherPage<br />

• Check the Replace Instances of Class Name box.<br />

242 <strong>Using</strong> <strong>Zen</strong>


with an Object Data Model<br />

• Click OK.<br />

The new class definition for MyApp.MyOtherPage displays in Studio.<br />

9. Take a shortcut by leaving the id as "patientData".<br />

You may ignore this shortcut by globally replacing "patientData" with a more meaningful id, for<br />

example "employeeData". However, make sure you change all the instances of this id string in<br />

the class, or you will encounter errors at runtime.<br />

10. Change the modelClass to "MyApp.EmployeeModel".<br />

11.<br />

12.<br />

Choose Build > Compile or Ctrl-F7 or the icon.<br />

Choose View > Web Page or the icon.<br />

The following figure shows the resulting form, with the values for record 5.<br />

has chosen controls for this form as follows:<br />

• for the Name, which is a %String<br />

• for the Salary, which is %Numeric<br />

• for the Active status, which is a %Boolean<br />

<strong>Using</strong> <strong>Zen</strong> 243


Model View Controller<br />

Property Type<br />

Boolean<br />

Date<br />

Date<br />

Enumerated<br />

Enumerated<br />

Numeric<br />

Object reference<br />

Stream<br />

Stream<br />

String<br />

String<br />

Public properties<br />

Private properties<br />

Controls Based on Property Types<br />

Details<br />

—<br />

In YYYY-MM-DD format<br />

In other formats<br />

<strong>Using</strong> a VALUELIST with 4 or fewer values<br />

<strong>Using</strong> a VALUELIST with more than 4 values<br />

—<br />

generates an SQL query<br />

Character<br />

Binary<br />

With MAXLEN over 250<br />

With MAXLEN between 1 and 250<br />

All types not listed above<br />

Any properties marked private<br />

Control<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Not displayed<br />

If you do not like the choices that makes, you can switch to and bind each control<br />

to a property individually, using the dataBinding attribute.<br />

13.6 with an Adaptor Data Model<br />

This topic explains how to use with a data controller when the data model is an adaptor<br />

data model. This approach is particularly convenient when you have an existing class with a large<br />

number of properties that you need to display on a form. In that case it would be extremely time-consuming<br />

to add these properties one by one to a subclass of %ZEN.DataModel.ObjectDataModel, as<br />

demonstrated in the previous topics. can save coding time, especially when you use it in<br />

combination with a subclass of %ZEN.DataModel.Adaptor. All you need to do then is to create a <strong>Zen</strong><br />

page class whose contains a and a . Your subclass of<br />

%ZEN.DataModel.Adaptor becomes the model, the view, and the controller, all in one. All of its properties<br />

become controls on the resulting . <strong>Zen</strong> generates the appropriate control type for<br />

property automatically.<br />

244 <strong>Using</strong> <strong>Zen</strong>


with an Adaptor Data Model<br />

13.6.1 Step 1: Generating the Form<br />

The basic outline for using with an adaptor data model is as follows:<br />

Note:<br />

This example is based on the <strong>Zen</strong> classes ZENMVC.MVCDynaForm, ZENMVC.Person, and<br />

ZENMVC.Address in the SAMPLES namespace.<br />

1. Edit a persistent class so that it also extends %ZEN.DataModel.Adaptor, for example:<br />

Class ZENMVC.Person Extends (%Persistent, %ZEN.DataModel.Adaptor)<br />

{<br />

Property Name As %String [ Required ];<br />

}<br />

Property SSN As %String;<br />

Property Salary As %Numeric;<br />

Property Active As %Boolean;<br />

Property Home As Address;<br />

Property Business As Address;<br />

The Person class includes properties defined by another class, Address, which must also extend<br />

%ZEN.DataModel.Adaptor but which need not be persistent, for example:<br />

Class ZENMVC.Address Extends (%SerialObject, %ZEN.DataModel.Adaptor)<br />

{<br />

Property City As %String(MAXLEN = 50);<br />

Property State As %String(MAXLEN = 2);<br />

Property Zip As %String(MAXLEN = 15);<br />

}<br />

2. Compile both data model classes.<br />

3. Create a new <strong>Zen</strong> page class.<br />

4. In XData Contents, place a and inside :<br />

<br />

<br />

<br />

<br />

5. Compile the <strong>Zen</strong> page class.<br />

6.<br />

Choose View > Web Page or the<br />

icon.<br />

generates the appropriate controls and displays the form, for example:<br />

<strong>Using</strong> <strong>Zen</strong> 245


Model View Controller<br />

13.6.2 Step 2: Property Parameters<br />

Once you have the basics in place, you may refine the form by assigning data model parameters to the<br />

properties in the persistent class that you are using as an adaptor data model. For example:<br />

1. Open the data model class Person from the previous exercise.<br />

2. Add data model parameters to the properties as shown below:<br />

Class ZENMVC.Person Extends (%Persistent, %ZEN.DataModel.Adaptor)<br />

{<br />

Property Name As %String (ZENLABEL = "Employee Name") [ Required ];<br />

Property SSN As %String (ZENREADONLY = 1);<br />

Property Salary As %Numeric (ZENHIDDEN = 1);<br />

Property Active As %Boolean (ZENLABEL = "Is this person working");<br />

Property Home As Address;<br />

Property Business As Address;<br />

}<br />

3. Compile the <strong>Zen</strong> page class.<br />

4.<br />

Choose View > Web Page or the<br />

icon.<br />

generates the appropriate controls and displays the form, for example:<br />

246 <strong>Using</strong> <strong>Zen</strong>


with an Adaptor Data Model<br />

The data model parameters have the following effects:<br />

• ZENHIDDEN hides the control associated with that property.<br />

• ZENLABEL replaces the default label (the property name) with a custom string.<br />

• ZENREADONLY displays the control but prevents the user from editing its contents.<br />

Note:<br />

A full list of parameters is available at the end of this chapter, in the topic Data Model Classes,<br />

subtopic Data Model Property Parameters.<br />

13.6.3 Step 3: Adding Behavior to the <br />

Adding behavior to a is quite similar to the steps outlined in the earlier topic, Adding<br />

Behavior to the :<br />

1. Open the <strong>Zen</strong> page class from the previous exercise.<br />

2. Add a control to display the current model ID value, and buttons to permit Update, New,<br />

and Save operations, as follows:<br />

<strong>Using</strong> <strong>Zen</strong> 247


Model View Controller<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

3. Add the corresponding new client-side methods to the page class:<br />

Method loadRecord(id) [ Language = javascript ]<br />

{<br />

var controller = zenPage.getComponentById('source');<br />

}<br />

controller.setModelId(id);<br />

And:<br />

Method showRecord() [ Language = javascript ]<br />

{<br />

var controller = zenPage.getComponentById('source');<br />

}<br />

controller.update();<br />

And:<br />

Method newRecord() [ Language = javascript ]<br />

{<br />

var text = zenPage.getComponentById('idText');<br />

text.setValue("");<br />

var controller = zenPage.getComponentById('source');<br />

controller.createNewObject();<br />

}<br />

And:<br />

Method save() [ Language = javascript ]<br />

{<br />

var form = zenPage.getComponentById('MyForm');<br />

}<br />

form.save();<br />

4. Compile the <strong>Zen</strong> page class.<br />

5.<br />

Choose View > Web Page or the icon.<br />

6. Click the New button.<br />

7. Enter data in the fields (except ID) and click Save.<br />

8. Click the New button again, just to clear the fields.<br />

248 <strong>Using</strong> <strong>Zen</strong>


with an Adaptor Data Model<br />

9. Enter the number 1 in the ID field and click Update. The corresponding record displays. For<br />

example:<br />

Since you have provided no special format for model ID values in the Person class, the default<br />

prevails. This means each new record you add gets a sequential number starting at 1. You may<br />

add more records by repeating steps 6 and 7. The numbers increment automatically.<br />

If you try to view a record by entering an ID number that does not exist, the displays<br />

with all of its fields disabled. You may click New to redisplay an active form in which to enter<br />

data for a new record.<br />

13.6.4 Step 4: Virtual Properties<br />

If you want to interject changes in a data model before using it, you can override the<br />

%OnGetPropertyInfo method in the data model class. This is the way to add virtual properties that<br />

you want to use in the model, but that do not exist in the class that you began with. You can use<br />

%OnGetPropertyInfo with either type of data model, but it makes the most sense for an adaptor data<br />

model because in that case you are using an existing class as a data model.<br />

<strong>Using</strong> <strong>Zen</strong> 249


Model View Controller<br />

This exercise adds a %OnGetPropertyInfo method to the adaptor data model class Person from the<br />

previous exercises.<br />

1. Open the Person class in Studio.<br />

2. Choose Class > Override.<br />

3. Select %OnGetPropertyInfo and click OK.<br />

Studio adds a skeleton %OnGetPropertyInfo method to the class.<br />

4. Edit the method as follows:<br />

These statements add a and a to any generated by the model.<br />

ClassMethod %OnGetPropertyInfo(pIndex As %Integer,<br />

ByRef pInfo As %String,<br />

pExtended As %Boolean = 0) As %Status<br />

{<br />

#; Increment past the 3 embedded properties from the last Address object.<br />

#; This is not necessary when the last property in the Person object<br />

#; is a simple data type such as %String or %Boolean or %Numeric.<br />

Set pIndex = pIndex + 3<br />

#; add a field at the end of the form<br />

Set pInfo("Extra") = pIndex<br />

Set pInfo("Extra","%type") = "checkbox"<br />

Set pInfo("Extra","caption") = "Extra!"<br />

Set pInfo("Extra","label") = "This is an extra checkbox."<br />

Set pIndex = pIndex + 1<br />

#; add another field at the end of the form<br />

Set pInfo("Comments") = pIndex<br />

Set pInfo("Comments","%type") = "textarea"<br />

Set pInfo("Comments","caption") = "Please enter additional comments:"<br />

Set pIndex = pIndex + 1<br />

}<br />

Quit $$$OK<br />

5. Recompile the Person class.<br />

6. There is no need to recompile the Address class or the <strong>Zen</strong> page class.<br />

7. View the <strong>Zen</strong> page that contains the associated , it generates the appropriate controls<br />

and displays the form, for example:<br />

250 <strong>Using</strong> <strong>Zen</strong>


Data Model Classes<br />

13.7 Data Model Classes<br />

The basic behavior of data models comes from the base class %ZEN.DataModel.DataModel. This class<br />

defines the basic data model interface which is, in turn, implemented by subclasses. A data model<br />

class can be one of the following types:<br />

• The data model class serves as a wrapper for an independent data source. The data model object<br />

provides the interface and the source object (or objects) provide the actual data. In this case the<br />

data model class must implement the additional callback methods related to the data source object.<br />

Our form examples followed this convention by subclassing %ZEN.DataModel.ObjectDataModel<br />

and overriding several server-side callback methods.<br />

• The data model class is also the data source object. The data model object provides both the data<br />

and the interface. In this case, there is no need to override the callback methods related to the data<br />

source object. All you need to do is to make your data source class implement the<br />

<strong>Using</strong> <strong>Zen</strong> 251


Model View Controller<br />

%ZEN.DataModel.Adaptor interface. Then you can use the resulting class directly as the modelClass<br />

for the component in your page class.<br />

13.7.1 Data Model Class Properties<br />

The %ZEN.DataModel.DataModel class provides the following properties:<br />

• String that identifies the currently active instance of the data model object, also known as the<br />

model ID. This value can be initially set by providing a modelId attribute in the <br />

definition. The exact form and possible values of the model ID are up to the developer of a specific<br />

data model class. The property names are:<br />

- id — Use in JavaScript code that runs on the client side<br />

- %id — Use in ObjectScript or Basic code that runs on the server side<br />

For examples, see the exercises in Adding Behavior to the .<br />

• Array of strings that provide display names for the data series in the model. Each string labels one<br />

data series. The array is subscripted by series number (1–based). The property names are:<br />

- seriesNames — Use in JavaScript code that runs on the client side<br />

- %seriesNames — Use in ObjectScript or Basic code that runs on the server side<br />

• Number of data series contained within the data model. The property names are:<br />

- seriesCount — Use in JavaScript code that runs on the client side<br />

- %seriesCount — Use in ObjectScript or Basic code that runs on the server side<br />

For details about series, see Data Model Series, later in this topic.<br />

13.7.2 Data Model Class Parameters<br />

Data model classes provide class parameters that determine the type of data model. The following<br />

table lists them.<br />

252 <strong>Using</strong> <strong>Zen</strong>


Data Model Classes<br />

Data Model Class Parameters<br />

Property Parameter<br />

READONLYMODEL<br />

DYNAMICPROPERTIES<br />

Description<br />

1 (true) or 0 (false). If true, indicates that this is a read-only<br />

model. It can be used to display data but not to generate<br />

editable forms. The default is 0 (false).<br />

1 (true) or 0 (false). If true, indicates that this model supports<br />

virtual properties as described in the exercise <br />

with an Adaptor Data Model, Step 4: Virtual Properties, and<br />

in the later topic Virtual Properties. The default is:<br />

• 1 (true) for %ZEN.DataModel.ObjectDataModel<br />

• 0 (false) for %ZEN.DataModel.Adaptor<br />

13.7.3 Data Model Property Parameters<br />

The %ZEN.DataModel.DataModel class provides property parameters that you can apply to the data<br />

model properties that you wish to use as controls on a form. These parameters let you provide more<br />

specific control over the properties of the data model class. The utility class<br />

%ZEN.DataModel.objectModelParameters defines these parameters; the following table lists them.<br />

Note:<br />

For examples, use Studio to view the classes ZENMVC.FormDataModel and<br />

ZENMVC.FormDataModel2 in the SAMPLES namespace. Also see the exercises in<br />

with an Adaptor Data Model.<br />

Data Model Property Parameters<br />

Property Parameter<br />

ZENATTRS<br />

Description<br />

List of additional attributes to apply to the control used for this<br />

property. This string should have the following form:<br />

"attribute:value|attribute:value"<br />

ZENCONTROL<br />

ZENDISPLAYCOLUMN<br />

Type of control used to display this property within a form; If<br />

not defined, <strong>Zen</strong> chooses the control type based on the data<br />

type of the property.<br />

If defined, this is the name of the column used to provide a<br />

display value for SQL statements automatically generated for<br />

this property.<br />

<strong>Using</strong> <strong>Zen</strong> 253


Model View Controller<br />

Property Parameter<br />

ZENGROUP<br />

ZENHIDDEN<br />

ZENLABEL<br />

ZENREADONLY<br />

ZENSIZE<br />

ZENSQL<br />

ZENSQLLOOKUP<br />

ZENTAB<br />

ZENTITLE<br />

Description<br />

The id of a group component that the control used for this<br />

property should be added to. This provides a way to control<br />

layout. If not defined, the control is added directly to the form.<br />

1 (true) or 0 (false). If true, indicates that this is a hidden field.<br />

When the value of this field is sent to the client, it is not<br />

displayed. The default is 0 (false).<br />

Label used for this property within a form.<br />

1 (true) or 0 (false). If true, this is a read-only field and cannot<br />

be edited by the user. The default for is 0 (false).<br />

If specified, this overrides the default size of the control used<br />

to display the property within a form.<br />

If defined, this is an SQL statement used to find possible values<br />

for this property.This parameter corresponds to the sql property<br />

of the various data-driven <strong>Zen</strong> components. For details, see<br />

the chapter <strong>Zen</strong> Tables, topic Specifying an SQL Query.<br />

If defined, this is an SQL statement used to find the appropriate<br />

display value for a given logical value. This parameter<br />

corresponds to the sqlLookup property of the various data-driven<br />

<strong>Zen</strong> components. For details, see the chapter <strong>Zen</strong> Controls,<br />

topic Lists, subtopic Logical and Display Values.<br />

A positive integer. If specified, this will override the (1–based)<br />

default tab order of the control used to display the property<br />

within a form. All controls with ZENTAB specified are placed<br />

before controls that do not define it.<br />

Optional popup title string displayed for this property within a<br />

form.<br />

13.7.4 Object Data Model Callback Methods<br />

When you create an object data model, you subclass %ZEN.DataModel.ObjectDataModel and provide<br />

implementations for its server-side callback methods. The following table describes these methods in<br />

detail. You first encountered several of these methods in the exercise topic Constructing a Model, Step<br />

2: Object Data Model; the Example column indicates these.<br />

254 <strong>Using</strong> <strong>Zen</strong>


Data Model Classes<br />

Object Data Model Callback Methods<br />

Method<br />

%OnDeleteModel<br />

%OnDeleteSource<br />

%OnGetPropertyInfo<br />

%OnInvokeAction<br />

%OnLoadModel<br />

%OnNewSource<br />

%OnOpenSource<br />

%OnSaveSource<br />

%OnStoreModel<br />

Example<br />

—<br />

Yes<br />

—<br />

—<br />

Yes<br />

Yes<br />

Yes<br />

Yes<br />

Yes<br />

This Callback Method is Invoked When...<br />

The data model is deleted. This method is<br />

implemented by the subclasses of the data model<br />

class, if they exist.<br />

The data model is deleted. If implemented, it is<br />

responsible for deleting the object that has the given<br />

id and returning the status code resulting from that<br />

operation.<br />

The %GetPropertyInfo method invokes it. See the<br />

discussion following this table.<br />

A user-defined, named action is invoked on this<br />

model object. See the discussion following this table.<br />

This method is implemented by the subclasses of<br />

the data model class, if they exist.<br />

<strong>Zen</strong> does the actual work of loading values from the<br />

data source into the data model object.The only data<br />

to load is the data that is actually seen by the user.<br />

This is the place to perform any aggregation or other<br />

operations on the data before storing it.<br />

A data model needs a new instance. If implemented,<br />

it opens a new (unsaved) instance of the data source<br />

object used by the data model, and return its<br />

reference.<br />

A data model is opened. If implemented, it opens an<br />

instance of the data source object used by the data<br />

model, and returns its reference<br />

The data model is saved. If implemented, it is<br />

responsible for saving changes to the data source.<br />

It saves the given source object and return the status<br />

code resulting from that operation. Before returning<br />

the status code, it sets the data model’s %id property<br />

to the identifier for the source object.<br />

<strong>Zen</strong> does the actual work of copying values from the<br />

data model to the data source. This method loads<br />

data from the model (probably changed by the user<br />

through a form) back into the source object.<br />

<strong>Using</strong> <strong>Zen</strong> 255


Model View Controller<br />

Method<br />

%OnSubmit<br />

Example<br />

—<br />

This Callback Method is Invoked When...<br />

A form connected to this data model is submitted.<br />

The contents of this data model will be filled in from<br />

the submitted values before this callback is invoked.<br />

Implementing this callback is optional.<br />

13.7.5 Virtual Properties<br />

When a data controller needs to find information about the properties within a data model, it calls the<br />

data model’s %GetPropertyInfo method. This returns a multidimensional array containing details<br />

about the properties of the data model. The code that assembles this information is automatically<br />

generated based on the properties, property types, and property parameters of the data model class.<br />

A data model class can modify the property information returned by %GetPropertyInfo by overriding<br />

the %OnGetPropertyInfo callback method. %GetPropertyInfo invokes the %OnGetPropertyInfo<br />

immediately before it returns the property information. %OnGetPropertyInfo receives, by reference,<br />

the multidimensional array containing the property information. %OnGetPropertyInfo can modify<br />

the contents of this array as it sees fit. Properties can be added, removed, or have their attributes<br />

changed. Attributes that you add using this method are called virtual properties.<br />

Note:<br />

For examples, see the exercises in with an Adaptor Data Model, Step 4: Virtual<br />

Properties.<br />

The %OnGetPropertyInfo signature looks like this:<br />

ClassMethod %OnGetPropertyInfo(pIndex As %Integer,<br />

ByRef pInfo As %String,<br />

pExtended As %Boolean = 0,<br />

pModelId As %String = "",<br />

pContainer As %String = "") As %Status<br />

Where:<br />

• pIndex is the index number that should be used to add the next property to the list.<br />

• pInfo is a multidimensional array containing information about the properties of this data model.<br />

• If pExtended is true, then complete information about the properties should be returned; if false,<br />

then only property names need be returned (applications can simply ignore this).<br />

• pModelId is the id value of the current Data Model instance. This is provided for cases where the<br />

contents of a dynamic form may vary by instance of the Data Model object.<br />

• If this is an embedded property, pContainer is the name of the property that contains it.<br />

256 <strong>Using</strong> <strong>Zen</strong>


Within the %OnGetPropertyInfo method, the property information array pInfo is subscripted by<br />

property name. The top node for each property contains an integer index number used to determine<br />

the ordinal position of a property within a dynamically generated form:<br />

If you want %OnGetPropertyInfo to add a new property to a data model, simply add the appropriate<br />

nodes to the property information array. The new property will be treated as a “virtual” property. That<br />

is, you can set and get its value by name even though there is no property formally defined with this<br />

name. When adding a new property in %OnGetPropertyInfo, set the top level node to the current<br />

index number and then increment the index by 1:<br />

pInfo("Property") = pIndex<br />

Set pIndex = pIndex + 1<br />

The property information array has a number of subnodes that can be defined to provide values for<br />

other property attributes. Built-in attributes start with % and include:<br />

• pInfo("Property","%type") = "control"<br />

The %type subnode identifies the name of the <strong>Zen</strong> control that should be used for properties of<br />

this type when using a dynamic form. Note that this name is the class name of a component. If<br />

no package name is provided, it is assumed that this is a component in the %ZEN.Component<br />

package. Use a full class name if you wish to specify a component from a different package.<br />

• pInfo("Property","%group") = "groupId"<br />

The %group subnode indicates the id of a group component contained by a dynamic form. If<br />

%group is specified and there is a group with this id, then the control for this property will be<br />

created within this group. This provides a way to control the layout of controls within a dynamic<br />

form.<br />

Attributes that do not start with a % specify values that should be applied to a property of the control<br />

with the same name. For example, the following statement causes a dynamic form to set the label<br />

property of the control used for the MyProp property to "My Label".<br />

Set pInfo("MyProp","label") = "This is an extra field!"<br />

Data Model Classes<br />

Data models and data controllers each support the %OnGetPropertyInfo method. At runtime, the<br />

order in which <strong>Zen</strong> adds controls to the generated form is as follows:<br />

1. Creates an initial list of controls based on the data model properties and their parameters.<br />

2. Modifies this list of controls by calling the data model’s %OnGetPropertyInfo method, if present.<br />

3. Further modifies this list of controls by calling the data controller’s %OnGetPropertyInfo method,<br />

if present.<br />

<strong>Using</strong> <strong>Zen</strong> 257


Model View Controller<br />

13.7.6 Controller Actions<br />

The %OnInvokeAction callback lets you define “actions” that can be invoked on the data model via<br />

the data controller. The client can invoke an action by calling the dataController’s invokeAction<br />

method as follows:<br />

controller.invokeAction('MyAction',data);<br />

This, in turn, invokes the server-side %OnInvokeAction callback of the data model, passing the name<br />

of the action and the data value. The interpretation of the action name and data is up to the application<br />

developer.<br />

13.7.7 Data Model Series<br />

The basic data model object consists of a series of name-value pairs.<br />

Data Model with Name-Value Pairs<br />

The name-value pairs in the data model comprise all of the properties in the data model class, minus<br />

those properties marked ZENHIDDEN, plus any properties added by %OnGetPropertyInfo, minus<br />

any properties deleted by %OnGetPropertyInfo. By default, the number of series is 1, but it could<br />

be larger. If there are multiple series in the model, conceptually it becomes a matrix.<br />

258 <strong>Using</strong> <strong>Zen</strong>


Data Model Classes<br />

Data Model with Data Series<br />

You can add multiple series to the model if you write your own %OnLoadModel method, as in the<br />

SAMPLES class ZENMVC.ChartDataModel2, shown below. This example creates three series for the<br />

model and assigns values to data model properties in each of the series.<br />

Class ZENMVC.ChartDataModel2 Extends %ZEN.DataModel.ObjectDataModel<br />

{<br />

Property Cars As %Integer;<br />

Property Trucks As %Integer;<br />

Property Trains As %Integer;<br />

Property Airplanes As %Integer;<br />

Property Ships As %Integer;<br />

Method %OnLoadModel(pSource As %RegisteredObject) As %Status<br />

{<br />

Set scale = 100<br />

}<br />

#; This model has multiple data series. We set up the data series here.<br />

Set ..%seriesCount = 3<br />

Set ..%seriesNames(1) = "USA"<br />

Set ..%seriesNames(2) = "Europe"<br />

Set ..%seriesNames(3) = "Asia"<br />

#; Now we provide data for each property within each series.<br />

#; We use the %data array so that we can address multiple series.<br />

For n = 1:1:..%seriesCount {<br />

Set ..%data(n,"Cars") = $RANDOM(100) * scale<br />

Set ..%data(n,"Trucks") = $RANDOM(100) * scale<br />

Set ..%data(n,"Trains") = $RANDOM(100) * scale<br />

Set ..%data(n,"Airplanes") = $RANDOM(100) * scale<br />

Set ..%data(n,"Ships") = $RANDOM(100) * scale<br />

}<br />

Quit $$$OK<br />

}<br />

When your data model has multiple series, if you bind the data model to a chart, the chart automatically<br />

picks up the various series, although you need to be careful with a pie chart. Series work similarly for<br />

<strong>Using</strong> <strong>Zen</strong> 259


Model View Controller<br />

a grid. A form can only display one series at a time, so you need to rely on the data controller attribute<br />

defaultSeries to determine which series is currently in view.<br />

13.7.8 Custom Data Model Classes<br />

%ZEN.DataModel.ObjectDataModel or %ZEN.DataModel.Adaptor are sufficient for most needs. However,<br />

sometimes a developer might want to create a special category of data model, for example to represent<br />

a global. In that case the developer must subclass %ZEN.DataModel.DataModel and implement the<br />

details of this subclass.<br />

The following table lists methods that applications can call in order to work with a data model object.<br />

The behavior of these methods is up to the specific %ZEN.DataModel.DataModel subclass that implements<br />

them.<br />

Custom Data Model Class Methods<br />

Method<br />

%DeleteModel<br />

%OpenModel<br />

%SaveModel<br />

Description<br />

Delete an instance of a data model object given an identifier value.<br />

This takes the given identifier value and uses it to delete an instance<br />

of a source object (if applicable). (If the data model object serves as<br />

both interface and data source, then the data model object itself is<br />

deleted).<br />

Open an instance of a data model object given an identifier value.<br />

This takes the given identifier value and uses it to find an instance<br />

of a source object (if applicable) and then copies the appropriate<br />

values of the source object into the properties of the data model<br />

object. (If the data model object serves as both interface and data<br />

source, then this copying is not carried out).<br />

Save an instance of a data model object. This copies the properties<br />

of the data model object back to the appropriate source object (if<br />

applicable) and then asks the source object to save itself. (If the data<br />

model object serves as both interface and data source, then the data<br />

model itself is saved.).<br />

260 <strong>Using</strong> <strong>Zen</strong>


14<br />

Navigation Components<br />

The <strong>Zen</strong> Layout chapter, Groups topic introduced <strong>Zen</strong> group components as the key to laying out the<br />

<strong>Zen</strong> page. That chapter described the simple group components , , , ,<br />

and .<br />

This chapter describes a more complex set of group and menu components. A developer can use these<br />

components to support navigation through <strong>Zen</strong> applications:<br />

• Links — Link to other <strong>Zen</strong> pages, or other application content, via a URI.<br />

• Menus — Present and manage a structured set of choices, usually links.<br />

• Tabs — Define tabbed menus and tabbed forms.<br />

• — Display a group that expands or contracts when the user clicks on an icon.<br />

The following table organizes <strong>Zen</strong> navigation components into two categories: containers (at left) and<br />

contained (at right). This chapter describes each component in the order listed in the table.<br />

<strong>Using</strong> <strong>Zen</strong> 261


Navigation Components<br />

Container<br />

(Any)<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Purpose<br />

Provide a link to another page<br />

or to a popup message.<br />

Navigation bar for the top of<br />

the page.<br />

Menu container. The default<br />

layout is vertical but you can<br />

use the layout attribute to<br />

change to horizontal layout.<br />

Alternatively, you may use<br />

or .<br />

Horizontally oriented menu<br />

Vertically oriented menu<br />

Traditional set of tabs from<br />

which the user can choose<br />

one to be displayed on top of<br />

the set.<br />

A tabbed menu that displays<br />

a button for each tab. Clicking<br />

on a button makes the tab<br />

contents display beneath the<br />

button. Each tab consists of<br />

menu items.<br />

A tab is a group that may<br />

contain any combination of<br />

components.<br />

Expanding and contracting<br />

group which may contain any<br />

combination of components.<br />

Components It Typically Contains<br />

for each link.<br />

for each link in the<br />

navigation sequence.<br />

for each option.<br />

for the space<br />

between options.<br />

for each option.<br />

Inside a , each <br />

contains and<br />

components.<br />

For a simple navigation tree, you can<br />

provide components within<br />

.<br />

The following figure lists the components described in this chapter. All of the classes shown in the<br />

diagram are in the package %ZEN.Component, for example %ZEN.Component.tab. The diagram shows<br />

the inheritance relationships for these classes. It also highlights which of these components can contain<br />

other components, by showing which components inherit from %ZEN.Component.group.<br />

262 <strong>Using</strong> <strong>Zen</strong>


Links<br />

<strong>Zen</strong> Navigation Components<br />

14.1 Links<br />

The following <strong>Zen</strong> components provide links to content that is available via a URI:<br />

• <br />

• <br />

14.1.1 <br />

The component outputs a simple link (an HTML anchor element) to the <strong>Zen</strong> page. The default<br />

formatting for this type of link is to use color and underline it. has the following attributes.<br />

Attribute<br />

<strong>Zen</strong><br />

component<br />

attributes<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> component.<br />

The chapter <strong>Zen</strong> Style describes them.<br />

<strong>Using</strong> <strong>Zen</strong> 263


Navigation Components<br />

Attribute<br />

caption<br />

disabled<br />

href<br />

Description<br />

Text for this link in the <strong>Zen</strong> page display.<br />

The caption value can be a literal string, or it can contain a <strong>Zen</strong> #()#<br />

expression. See <strong>Zen</strong> Runtime Expressions.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

If true, this link is disabled. The default is false. A newly disabled link is<br />

redisplayed, without an anchor tag, to ensure that it is truly disabled from<br />

the user’s point of view.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

URI of the content to display when the user clicks the caption text. If you<br />

want to invoke a client-side JavaScript method in the href, start the URI<br />

with javascript: as in:<br />

href="javascript:zenPage.myMethod();"<br />

The href value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

onclick<br />

(Optional) Client-side JavaScript expression that <strong>Zen</strong> invokes when the<br />

user clicks on the link. Generally this expression invokes a client-side<br />

JavaScript method.This method becomes the “onclick handler” for the link.<br />

If onclick is specified, href is ignored. If onclick is not specified, the link<br />

displays the content specified by href.<br />

When providing a value for an event handler attribute such as onclick, use<br />

double quotes to enclose the value and single quotes (if needed) within<br />

the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

style<br />

CSS style to apply to cells in this link, for example:<br />

color: red;<br />

264 <strong>Using</strong> <strong>Zen</strong>


Links<br />

Attribute<br />

title<br />

Description<br />

Help message to display when the user hovers the cursor over the link,<br />

without clicking.<br />

The title value can be a literal string, or it can contain a <strong>Zen</strong> #()# expression.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

One way to use is to place it within an component to present a tree-style menu of<br />

links.<br />

14.1.2 <br />

A looks like the following example, based on the class ZENTest.FormTest in the SAM-<br />

PLES namespace:<br />

The corresponding definition follows. As this example shows, entries<br />

within the display their caption values on the <strong>Zen</strong> page in sequential order, from left to<br />

right. The text for each caption is enclosed in square brackets. Captions are further separated by a right<br />

angle bracket to indicate the navigation sequence. The next topic provides additional details about<br />

attributes.<br />

<br />

<br />

<br />

<br />

<br />

has the following attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 265


Navigation Components<br />

Attribute<br />

<strong>Zen</strong> component<br />

attributes<br />

OnGetQuickLinks<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong><br />

component. The chapter <strong>Zen</strong> Style describes them.<br />

(Optional) Name of a server-side method that returns an array of<br />

“quick links.” If provided, these links are displayed in a dropdown<br />

list at the edge of the locator bar. The array is of the form:<br />

pLink("caption")=url<br />

The OnGetQuickLinks value must be the name of a server-only<br />

method in the page class that contains this form component.<br />

14.1.3 <br />

can appear only inside the container. Each defines one<br />

link within the navigation chain expressed in the . is the XML projection<br />

of the auxiliary class %ZEN.Auxiliary.locatorLink. has the following attributes.<br />

Attribute<br />

id<br />

name<br />

caption<br />

href<br />

Description<br />

This value can be used to select a CSS style definition for the .<br />

Component name. Typically, this is not used for .<br />

Text for this link in the .<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

URI of the content to display when the user clicks the caption text. If you<br />

want to invoke a client-side JavaScript method in the href, start the URI with<br />

javascript: as in:<br />

link="javascript:zenPage.myMethod();"<br />

title<br />

Help message to display when the user hovers the cursor over the link,<br />

without clicking.<br />

Although you enter ordinary text for this attribute, it has the underlying data<br />

type %ZEN.Datatype.caption. This makes it easy to localize its text into other<br />

languages. See <strong>Zen</strong> Localization.<br />

266 <strong>Using</strong> <strong>Zen</strong>


Menus<br />

14.2 Menus<br />

Menu components permit you to create classic navigation menus, with lists of choices from which the<br />

user can select an item by clicking on it. With each choice of a menu item, an event may occur<br />

depending on how the menu and menu item have been defined:<br />

• A submenu might display<br />

• A message might pop up<br />

• A different page might display<br />

• The contents of the current page might change<br />

• Something else might happen, depending on how you have programmed the menu to respond<br />

when the user selects each <br />

A vertical menu, expanded to three levels, looks like the following example, based on the class<br />

ZENTest.MenuTest in the SAMPLES namespace. Any options that produce submenus use the » right<br />

angle quote to indicate this, as shown for “Submenu” and “Sub Submenu”.<br />

The definition that produced this illustration is shown below:<br />

<strong>Using</strong> <strong>Zen</strong> 267


Navigation Components<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

The next several topics explain details of the menu components in this example. For now, simply note:<br />

• In many cases, the example uses JavaScript alerts in place of URI links for demonstration purposes.<br />

link values can take this form, or they can redirect the browser to other pages in the <strong>Zen</strong> application,<br />

as the example shows:<br />

• A can contain a . If so, the contained becomes a submenu and its caption<br />

is listed in sequence along with any components at the same level. The above<br />

example provides three levels of .<br />

• The example provides a on the first- and third-level menus. Note how the<br />

component generates the divider bar between “Submenu” and “Test Suite” and<br />

between “Sub Submenu” and “Help Desk” in the output.<br />

14.2.1 <br />

Each item on a is defined using . has the following attributes. Since<br />

either of them may display their caption or image as a choice within a menu cell, and<br />

share all of these attributes in common. has additional attributes; the next topic<br />

describes them.<br />

Menu Cell Attributes<br />

Attribute<br />

<strong>Zen</strong><br />

component<br />

attributes<br />

Description<br />

and have the same general-purpose attributes<br />

as any <strong>Zen</strong> component. The chapter <strong>Zen</strong> Style describes them.<br />

268 <strong>Using</strong> <strong>Zen</strong>


Menus<br />

Attribute<br />

caption<br />

disabled<br />

help<br />

image<br />

Description<br />

Text for this menu item when it appears as a choice within its containing<br />

.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

If true, this menu item is disabled. The default is false.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

The help attribute supplies help text for this menu item.<br />

Generally what you want in place of help is the title attribute. title supplies<br />

tooltip text that displays whenever the user hovers the mouse over this<br />

item. All <strong>Zen</strong> components, including and , support<br />

the title attribute.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

Identifies the pathname and filename of an image to display for this<br />

menu item. If both image and caption are provided, they appear side<br />

by side, teh image at left and the text at right.<br />

The image path is relative to the Caché installation directory. Typically<br />

this path identifies the images subdirectory for your <strong>Zen</strong> application, for<br />

example:<br />

<br />

imageHeight<br />

imageWidth<br />

link<br />

If an image is provided, imageHeight is its height in pixels. The default<br />

is 16.<br />

If an image is provided, imageWidth is its width in pixels. The default is<br />

16.<br />

URI of the content to display when the user clicks the menu item. If you<br />

want to invoke a client-side JavaScript method in the link, start the URI<br />

with javascript: as in:<br />

link="javascript:zenPage.myMethod();"<br />

<strong>Using</strong> <strong>Zen</strong> 269


Navigation Components<br />

Attribute<br />

linkResource<br />

onclick<br />

Description<br />

Name of a Caché resource. The user must have privileges to access<br />

this resource or this menu item becomes disabled. If you are not familiar<br />

with Caché resources, see the Caché Security Administration Guide<br />

chapter Assets and Resources.<br />

(Optional) Client-side JavaScript expression that <strong>Zen</strong> invokes when the<br />

user clicks on the menu item. Generally this expression invokes a clientside<br />

JavaScript method. This method becomes the “onclick handler” for<br />

the menu item.<br />

If onclick is specified, link is ignored. If onclick is not specified, the menu<br />

item displays the content specified by link.<br />

When providing a value for an event handler attribute such as onclick,<br />

use double quotes to enclose the value and single quotes (if needed)<br />

within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

14.2.2 , , and <br />

All <strong>Zen</strong> groups that do not have a predefined layout setting have a vertical layout by default. This is<br />

true for the component. However, it can be useful to explicitly state the desired layout of the<br />

menu group. You can do this by:<br />

• Setting a value for the layout attribute (as in the example above)<br />

• Choosing one of the following in place of :<br />

- — a horizontally oriented list of choices<br />

- — a vertically oriented list of choices<br />

, , and have the following attributes.<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

Description<br />

A menu has the same style and layout attributes as any <strong>Zen</strong> group. The<br />

chapter <strong>Zen</strong> Layout describes them. The layout attribute does not apply<br />

to or because these components have layout set to<br />

"horizontal" and "vertical" respectively.<br />

270 <strong>Using</strong> <strong>Zen</strong>


Tabs<br />

Attribute<br />

<strong>Zen</strong> menu<br />

cell attributes<br />

onactivate<br />

Description<br />

A menu may display its caption or image as a choice within a menu cell.<br />

For this reason, , , and share a number of<br />

attributes in common with . See the previous topic.<br />

If this menu is a submenu, onactivate is the client-side JavaScript<br />

expression that <strong>Zen</strong> invokes just before the submenu is made visible.<br />

Generally this expression invokes a client-side JavaScript method. This<br />

method becomes the “onactivate handler” for the menu.<br />

When providing a value for an event handler attribute such as onactivate,<br />

use double quotes to enclose the value and single quotes (if needed)<br />

within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

onshowHelp<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the user moves<br />

the mouse over this menu item. Generally this expression invokes a<br />

client-side JavaScript method.<br />

14.2.3 <br />

A bar helps to visually group the options on a . has the<br />

same general-purpose attributes as any <strong>Zen</strong> component. The chapter <strong>Zen</strong> Style describes them.<br />

has no additional attributes.<br />

14.3 Tabs<br />

The following <strong>Zen</strong> components support tabbed menus and forms for <strong>Zen</strong> applications:<br />

• <br />

• <br />

• <br />

<strong>Using</strong> <strong>Zen</strong> 271


Navigation Components<br />

14.3.1 <br />

A displays a set of components. It can only display one at a time. The user<br />

can choose one of these tabs to be displayed on top of the set. A looks like the following<br />

example, based on the class ZENTest.TabTest in the SAMPLES namespace.<br />

In the above example, the user has clicked the tab labelled “First Page.” In the following example, the<br />

user has clicked the tab labelled “Second Page” and has clicked the down-arrow to select a “Home<br />

City” option from the control.<br />

272 <strong>Using</strong> <strong>Zen</strong>


Tabs<br />

The definition that produces these illustrations is shown below:<br />

<strong>Using</strong> <strong>Zen</strong> 273


Navigation Components<br />

<br />

<br />

<br />

<br />

<br />

<br />

This is the first tab!<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

This is the second tab!<br />

<br />

<br />

<br />

<br />

This is the third tab!<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

has the following attributes. Since either or may display<br />

components, both and share these attributes in common. has additional attributes that distinguish it from ; the next topic describes them.<br />

274 <strong>Using</strong> <strong>Zen</strong>


Tabs<br />

Tab Group Attributes<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

currTab<br />

onhideTab<br />

Description<br />

and have the same style and layout<br />

attributes as any <strong>Zen</strong> group. The chapter <strong>Zen</strong> Layout describes them.<br />

1–based sequential number of the tab currently displayed. The default<br />

is 1.<br />

(Optional) Client-side JavaScript expression that <strong>Zen</strong> invokes when a<br />

previously displayed tab becomes hidden. Generally this expression<br />

invokes a client-side JavaScript method. This method becomes the<br />

“onhideTab handler” for the menu item.<br />

When providing a value for an event handler attribute such as onhideTab,<br />

use double quotes to enclose the value and single quotes (if needed)<br />

within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

onshowTab<br />

remember<br />

showTabBar<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when a previously<br />

hidden tab becomes the displayed tab. Generally this expression invokes<br />

a client-side JavaScript method.<br />

If true, remember the most recently displayed tab number in a session<br />

cookie and return to this tab when redisplayed. The default is false.<br />

remember has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

If true, display a set of tab buttons along the top of this group.The default<br />

is false.<br />

remember has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

14.3.2 <br />

A presents a stack of buttons, one for each tab. Clicking on a button shifts the other<br />

buttons down so that they display below the contents of the currently selected tab.<br />

<strong>Using</strong> <strong>Zen</strong> 275


Navigation Components<br />

The following example is based on the class ZENTest.LookoutMenuTest in the SAMPLES namespace.<br />

In the illustration, the user has clicked the “Animal” button to reveal the contents of that tab. This<br />

selection moved the remaining buttons to the bottom of the lookout menu. The cursor is now on the<br />

“Vegetables” menu item. If the user clicks this item, the contents of its link will be activated as defined<br />

in the corresponding .<br />

A contains a set of components, which in turn contain and<br />

components. These tabs are groups that can contain any component, but when they<br />

are present inside a they contain the components that would normally define a .<br />

The definition that produced the above illustration follows:<br />

276 <strong>Using</strong> <strong>Zen</strong>


Tabs<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

has the following attributes.<br />

Attribute<br />

<strong>Zen</strong> tab<br />

group<br />

attributes<br />

expandable<br />

Description<br />

shares a number of attributes in common with .<br />

See the previous topic. also has the attributes listed in this<br />

table.<br />

If true, this group is expandable. The default is false.<br />

When expandable is true, an expansion bar displays along the top of the<br />

as shown in the illustration above. The user clicks on this<br />

bar to toggle the expanded state of the . When the menu<br />

is contracted, only the expansion bar is visible. The user clicks the bar<br />

again to expand the .<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

<strong>Using</strong> <strong>Zen</strong> 277


Navigation Components<br />

Attribute<br />

expanded<br />

oncontract<br />

Description<br />

If true, this group is expanded (children visible). If false, it<br />

is contracted (children not visible). The default is true.<br />

expanded has the underlying data type %ZEN.Datatype.boolean. It has the<br />

value "true" or "false" in XData Contents, 1 or 0 in server-side code, true<br />

or false in client-side code. See Datatype Classes.<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes just before contracting<br />

(hiding) the children of this group. Generally this expression<br />

invokes a client-side JavaScript method. This method becomes the<br />

“oncontract handler” for the .<br />

When providing a value for an event handler attribute such as oncontract,<br />

use double quotes to enclose the value and single quotes (if needed) within<br />

the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

onexpand<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes just before expanding<br />

(displaying) the children of this group.<br />

14.3.3 <br />

A is a specialized group that defines a tab within a or . has<br />

the following attributes.<br />

278 <strong>Using</strong> <strong>Zen</strong>


Expanding Group<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

caption<br />

tabResource<br />

Description<br />

has the same style and layout attributes as any <strong>Zen</strong> group. The<br />

chapter <strong>Zen</strong> Layout describes them.<br />

Text for this tab when it appears as a choice within its containing or .<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

Name of a Caché resource.The user must have privileges to access this<br />

resource or this tab becomes disabled. If you are not familiar with Caché<br />

resources, see the Caché Security Administration Guide chapter Assets<br />

and Resources.<br />

14.4 Expanding Group<br />

The is a group with the ability to show or hide its children. A clickable graphic beside the<br />

label expands (displays) or contracts (hides) the contents of the group. A fully contracted<br />

group looks like the following example.<br />

The user expands the group by clicking on the plus sign beside its label. The contents of the<br />

then display below its label. As a <strong>Zen</strong> group, an may contain any type of <strong>Zen</strong><br />

component. In particular, each level of the may contain additional, nested <br />

groups that can be expanded or contracted independently of the containing group.<br />

In the following example, the user has just clicked on the plus sign to expand the group. The cursor is<br />

now poised to contract the by clicking the minus sign<br />

beside the label. This example<br />

<strong>Using</strong> <strong>Zen</strong> 279


Navigation Components<br />

contains three nested groups. The innermost uses a horizontal layout, and<br />

contains components instead of components as in the other levels.<br />

The definition that produced this example follows:<br />

280 <strong>Using</strong> <strong>Zen</strong>


Expanding Group<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

This definition references a number of methods defined in the page class. For example, the secondlevel<br />

references the server-side callback method DrawContent to produce additional formatted<br />

text, in this case a list of honors awarded to the author of the books listed. DrawContent looks<br />

like this:<br />

Method DrawContent(ByRef expando As %ZEN.Component.expando) As %Status<br />

{<br />

&html<br />

Quit $$$OK<br />

}<br />

The component has the following attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 281


Navigation Components<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

caption<br />

Description<br />

has the same style and layout attributes as any <strong>Zen</strong> group.<br />

The chapter <strong>Zen</strong> Layout describes them.The default layout<br />

is vertical.<br />

Text to display as the title of this group. This text displays<br />

even when the is contracted.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

childIndent<br />

expanded<br />

HTML length value giving the amount to indent the children in the<br />

expanded list of items. The above example uses 35px. The default is<br />

to use no indentation, aligning the children with the caption.<br />

If true, this group is expanded (children visible). If false, it<br />

is contracted (children not visible). The default is true.<br />

expanded has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

imageContracted<br />

(Optional) URI of the image to display when the group is<br />

contracted. The user clicks on this image to expand the group. The<br />

default for imageContracted is the plus sign<br />

whose URI is:<br />

/csp/broker/images/contracted.gif<br />

You may specify an alternate image. The path that you provide for<br />

imageContracted must be relative to the Caché installation directory.<br />

imageExpanded<br />

(Optional) URI of the image to display when the group is<br />

expanded. The user clicks on this image to contract the group. The<br />

default for imageExpanded is the minus sign<br />

whose URI is:<br />

/csp/broker/images/expanded.gif<br />

You may specify an alternate image. The path that you provide for<br />

imageExpanded must be relative to the Caché installation directory.<br />

282 <strong>Using</strong> <strong>Zen</strong>


Expanding Group<br />

Attribute<br />

oncontract<br />

Description<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes just before contracting<br />

(hiding) the children of this group. Generally this<br />

expression invokes a client-side JavaScript method. This method<br />

becomes the “oncontract handler” for the .<br />

When providing a value for an event handler attribute such as<br />

oncontract, use double quotes to enclose the value and single quotes<br />

(if needed) within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

OnDrawContent<br />

onexpand<br />

remember<br />

Optional. Name of a server-side callback method that provides<br />

additional HTML content for this component. If defined, this callback<br />

is invoked on the server when the component is drawn. It<br />

provides HTML content by using &html or the WRITE command.<br />

OnDrawContent must be the name of a server-only method in the page<br />

class that contains this view component; this method must return a<br />

%Status type.<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes just before<br />

expanding (displaying) the children of this group.<br />

If true, remember the most recent expanded state in a session cookie<br />

and return to this state when redisplayed. The default is false.<br />

remember has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

can be particularly useful in navigation when combined with .<br />

<strong>Using</strong> <strong>Zen</strong> 283


15<br />

Popup Windows and Dialogs<br />

This chapter describes <strong>Zen</strong> components that “pop up” to display their contents over the main application<br />

page. The tradeoff for the flexibility provided by these components is that you must provide more<br />

programming in the page class to make them effective. This chapter describes the following components:<br />

• Modal Groups — Make HTML content visible in response to a user event.<br />

• Popup Windows — Pop up a new window that displays a <strong>Zen</strong> page or any other content.<br />

• Dialogs — Pop up a dialog that prompts the user and accepts user input.<br />

15.1 Modal Groups<br />

A modal group is a specialized group component that normally does not display its contents. When<br />

the modal group is made visible, only its contents receive user events. Any event that occurs outside<br />

of the modal group (such as a mouse click) automatically hides the modal group. <strong>Zen</strong> uses this modal<br />

mechanism when it creates dropdown menus and dropdown combobox controls. You can also use this<br />

mechanism for popup items.<br />

You can define the contents of a modal group either by placing a component within<br />

the page class or by creating an instance of the %ZEN.Component.modalGroup class programmatically.<br />

There are three options:<br />

• Static — Place a component in the page class XData Contents block. Its contents<br />

remain hidden until a client-side method on the page calls the modalGroup show method.<br />

• Dynamic — Have the page call its createComponent method to create a modalGroup component<br />

dynamically. Add components to the group. Display it by calling the modalGroup show method.<br />

<strong>Using</strong> <strong>Zen</strong> 285


Popup Windows and Dialogs<br />

• Built-in — Have the page call the modalGroup show method to display one of the built-in modal<br />

groups: "msgBox" or "calendar"<br />

To close the current modal group, the page must invoke its endModal method. Generally endModal<br />

is triggered by an event handler for one of the buttons in the modal group (OK, Cancel, or similar). It<br />

is an error to call endModal if there is no modal group currently displayed.<br />

While a modal group has the editing focus, keyboard controls are disabled. For example, it is not<br />

possible to use Tab to move from field to field within the modal group. This prevents the user from<br />

(inadvertently) pressing Tab to navigate through all the fields and then back to the page, while the<br />

modal group has focus. The modal group keeps the focus until the user either clicks away from it or<br />

clicks the button that has been set up to close the modal group.<br />

Note:<br />

For Internet Explorer (IE) only: When displaying a modal group, <strong>Zen</strong> hides the contents of<br />

any elements (that is, SVG content). This is because IE ignores z-index setting for<br />

elements.<br />

15.1.1 Static Modal Groups<br />

In static mode, the modal group is defined within a page class XData Contents block using XML<br />

statements. The contents of the group are hidden until the modal group component’s show method is<br />

called; then they are displayed in a popup window.<br />

The following steps set this up in the page class:<br />

1. Supply a definition within the in XData Contents. For example:<br />

<br />

<br />

<br />

<br />

2. Provide a client-side method to display the modal group. For example:<br />

Method modalGroupStatic() [ Language = javascript ]<br />

{<br />

var group = this.getComponentById('mgStatic');<br />

}<br />

group.show();<br />

This method:<br />

• Finds the on the by calling getComponentById with the id value<br />

• Calls the client-side show method. No arguments are needed because the <br />

definition provides all the necessary information to show.<br />

286 <strong>Using</strong> <strong>Zen</strong>


3. Somewhere within the you must give the user a mechanism to invoke the<br />

modalGroupStatic method to display the modal group. The following example provides a button:<br />

<br />

4. For testing purposes, you may provide the with a field in which to echo the data from the<br />

popup:<br />

No data entered yet. <br />

The page XData Contents block now looks like this.<br />

<br />

No data entered yet. <br />

<br />

<br />

<br />

<br />

<br />

<br />

5. You must give the user a mechanism to close the popup. Additionally, if your popup invited the<br />

user to enter values, you will want to retrieve and use these values. The following client-side<br />

method in the page class does this:<br />

Method mgBtnClick() [ Language = javascript ]<br />

{<br />

// get value from text field<br />

var ctrl = zenPage.getComponentById('mgText');<br />

}<br />

// write user value into HTML component<br />

var html = zenPage.getComponentById('mgHtml');<br />

html.setProperty('content','User entered: ' + ctrl.getValue());<br />

// hide the modal group<br />

zenPage.endModal();<br />

This method:<br />

• Executes when the user clicks OK in the popup. This works because step 1 identified this<br />

method as the onclick event handler for the in the .<br />

• Finds the control from the by calling getComponentById with the<br />

id value<br />

• Gets the value entered into the control by calling getValue<br />

Modal Groups<br />

• Finds the component on the by calling getComponentById with the <br />

id value<br />

<strong>Using</strong> <strong>Zen</strong> 287


Popup Windows and Dialogs<br />

• Sets the content property of the component by calling setProperty. The new <br />

content concatenates a literal string with the newly-acquired value.<br />

• Calls the page’s endModal method to close the popup.<br />

The user may interact with this sample page as follows:<br />

1. The user initially sees:<br />

2. Clicking the button on this page invokes the modalGroupStatic method. This causes a window<br />

to pop up in front of the main page. The contents of the popup are the contents of the . The popup title is the groupTitle text.<br />

In the illustration below, the user has typed a value in the control within the popup:<br />

3. Clicking the OK button in this popup invokes the mgBtnClick method. This closes the popup<br />

and changes the contents of the component on the to echo the user input, as follows:<br />

The above example is similar to one available in the class ZENDemo.MethodTest in the SAMPLES<br />

namespace. You can try this sample from the <strong>Zen</strong> Demo main page by choosing Home, Overview,<br />

Methods, then Modal Group: Static.<br />

15.1.2 Dynamic Modal Groups<br />

In dynamic mode, the page creates a modal group component programmatically, by calling the clientside<br />

JavaScript methods createComponent, addChild, and setProperty. The sequence culminates<br />

in a call to the modalGroup show method with the appropriate arguments.<br />

The following steps set this up in the page class:<br />

1. Provide a client-side method to display the modal group. For example:<br />

288 <strong>Using</strong> <strong>Zen</strong>


Modal Groups<br />

Method modalGroupDynamic() [ Language = javascript ]<br />

{<br />

// create a modal group<br />

var group = this.createComponent('modalGroup');<br />

}<br />

// add components dynamically<br />

var col = this.createComponent('colorPicker');<br />

group.addChild(col);<br />

col.setProperty('id','myCol');<br />

var radio = this.createComponent('radioSet');<br />

group.addChild(radio);<br />

radio.setProperty('id','myRadio');<br />

radio.setProperty('valueList','elm,maple,oak');<br />

var btn = this.createComponent('button');<br />

group.addChild(btn);<br />

btn.setProperty('caption','Save');<br />

btn.setProperty('onclick','zenPage.btnClick();');<br />

// Show the group in "dynamic" mode.<br />

group.show('Dynamic Popup','dynamic',null,null,null,'236');<br />

This method:<br />

• Calls the page’s createComponent method to add a modalGroup component<br />

• Adds a colorPicker to the group<br />

- Calls the page’s createComponent method to create a colorPicker control<br />

- Calls the modal group’s addChild method to add the colorPicker to the group<br />

- Calls the color picker’s setProperty method to give the colorPicker an id value<br />

• Adds a radioSet to the group in the same way<br />

• Adds a button to the group in the same way<br />

• Calls the button’s setProperty method to set its onclick value to the name of a client-side<br />

method that will execute when the user clicks this button<br />

• Calls the modal group’s show method with these arguments:<br />

- A title for the popup window<br />

- The keyword 'dynamic'<br />

- The keyword null in argument positions three, four, and five<br />

- An optional width value of '236'<br />

For argument details see The show Method topic, below.<br />

2. Somewhere within the you must give the user a mechanism to invoke the<br />

modalGroupDynamic method to display the modal group. The following example provides a<br />

button:<br />

<strong>Using</strong> <strong>Zen</strong> 289


Popup Windows and Dialogs<br />

<br />

3. For testing purposes, you may provide the with a field in which to echo the data from the<br />

popup:<br />

No data entered yet. <br />

The page XData Contents block now looks like this.<br />

<br />

No data entered yet. <br />

<br />

<br />

4. You must give the user a mechanism to close the popup. Additionally, if your popup invited the<br />

user to enter values, you will want to retrieve and use these values. The following client-side<br />

method in the page class does this:<br />

Method btnClick() [ Language = javascript ]<br />

{<br />

// get values from controls<br />

var col = zenPage.getComponentById('myCol');<br />

var radio = zenPage.getComponentById('myRadio');<br />

}<br />

// write user values into HTML component<br />

var html = zenPage.getComponentById('mgHtml');<br />

html.setProperty('content','User entered: ' +<br />

col.getValue() + ' ' + radio.getValue());<br />

// hide the modal group<br />

zenPage.endModal();<br />

This method:<br />

• Executes when the user clicks Save in the popup. This works because step 1 identified this<br />

method as the onclick event handler for the Save button in the modal group.<br />

• Gets the color picker’s value as follows:<br />

- Finds the color picker control by calling getComponentById with the color picker id<br />

value<br />

- Gets the value entered into the color picker control by calling its getValue method<br />

• Gets the radio set’s value in the same way<br />

• Finds the component on the by calling getComponentById with the <br />

id value<br />

• Sets the content property of the component by calling setProperty. The new <br />

content concatenates a literal string with the newly-acquired color picker and radio set values.<br />

290 <strong>Using</strong> <strong>Zen</strong>


Modal Groups<br />

• Calls the page’s endModal method to close the popup.<br />

The user may interact with this sample page as follows:<br />

1. The user initially sees:<br />

2. Clicking the button on this page invokes the modalGroupDynamic method. This causes a window<br />

to pop up in front of the main page. The contents of the popup are the child components that<br />

modalGroupDynamic added. The popup title is the first argument that modalGroupDynamic<br />

passed to the show method.<br />

In the illustration below, the user has clicked on a color and a radio button:<br />

3. Clicking the Save button in this popup invokes the btnClick method. This closes the popup and<br />

changes the contents of the component on the as follows:<br />

15.1.3 Built-in Modal Groups<br />

In built-in mode, <strong>Zen</strong> dynamically creates and displays one of its built-in modal groups. This option<br />

is much simpler than the steps for a dynamic modal group. There are two options for built-in modal<br />

groups:<br />

• "calendar" — Display the built-in calendar box.<br />

• "msgBox" — Display the built-in message box.<br />

15.1.3.1 Calendar<br />

The following steps add a calendar popup to a <strong>Zen</strong> page class:<br />

1. Provide a client-side method to display the modal group.<br />

<strong>Using</strong> <strong>Zen</strong> 291


Popup Windows and Dialogs<br />

Method modalGroupCalendar() [ Language = javascript ]<br />

{<br />

var group = zenPage.createComponent('modalGroup');<br />

group.setProperty('onaction','zenPage.calendarAction(group);');<br />

group.show('Select a date:','calendar','2005-12-12');<br />

}<br />

This method:<br />

• Calls the page’s createComponent method to add a modalGroup component<br />

• Calls the modal group’s setProperty method to set its onaction value to the name of a clientside<br />

method that will execute when the user performs any action on this popup, such as<br />

selecting a date value from the calendar. This method accepts an argument, group, that represents<br />

the modalGroup instance.<br />

• Calls the modal group’s show method with three arguments:<br />

- A title for the popup window<br />

- The keyword 'calendar'<br />

- An optional pre-selected date for the calendar to display when it pops up<br />

2. Somewhere within the you must give the user a mechanism to invoke the method that<br />

displays the modal group. The following example provides a button:<br />

<br />

3. Finally, you must retrieve and use the date value acquired by the calendar control, and then close<br />

the popup. The following client-side method in the page class does this:<br />

Method calendarAction(group) [ Language = javascript ]<br />

{<br />

alert("You selected: " + group.getValue());<br />

}<br />

// write user value into HTML component<br />

var html = zenPage.getComponentById('mgHtml');<br />

html.setProperty('content','User entered: ' + group.getValue());<br />

This method:<br />

• Executes when the user clicks on a specific date value in the popup. This works because step<br />

1 identified this method as the onaction event handler for the modal group.<br />

• Calls the modal group’s getValue method to retrieve the date value entered into the calendar.<br />

• Issues a JavaScript alert message that confirms the value.<br />

• Finds the component on the by calling getComponentById with the <br />

id value<br />

292 <strong>Using</strong> <strong>Zen</strong>


Modal Groups<br />

• Sets the content property of the component by calling setProperty. The new <br />

content concatenates a literal string with the newly-acquired date value.<br />

• Does not call the page’s endModal method. The built-in calendar modal group closes automatically<br />

when the user chooses a date.<br />

The user may interact with this sample page as follows:<br />

1. The user initially sees:<br />

2. Clicking the button on this page invokes the modalGroupCalendar method. This causes a window<br />

to pop up in front of the main page. The popup title is the first argument that modalGroupCalendar<br />

passed to the show method. The currently selected date is the one specified by the third show<br />

argument.<br />

3. Selecting a different month, year, and date from the preselected value automatically invokes the<br />

calendarAction method. This closes the popup and displays a browser alert message that echoes<br />

the new date value:<br />

4. Dismissing the alert makes it easy to see that the contents of the component on the <br />

have now changed as follows:<br />

<strong>Using</strong> <strong>Zen</strong> 293


Popup Windows and Dialogs<br />

The above example is similar to one available in the class ZENDemo.MethodTest in the SAMPLES<br />

namespace. You can try this sample from the <strong>Zen</strong> Demo main page by choosing Home, Overview,<br />

Methods, and Modal Group: Calendar.<br />

15.1.3.2 Message Box<br />

The following steps add a message box popup to a <strong>Zen</strong> page class:<br />

1. Provide a client-side method to display the modal group.<br />

Method modalGroupMsg() [ Language = javascript ]<br />

{<br />

var group = this.createComponent('modalGroup');<br />

group.show('My New Message','msgBox',<br />

'Thismessagecontains HTML!');<br />

}<br />

This method:<br />

• Calls the page’s createComponent method to add a modalGroup component<br />

• Calls the modal group’s show method with three arguments:<br />

- A title for the popup window<br />

- The keyword 'msgBox'<br />

- HTML-formatted message content for the popup message<br />

2. Somewhere within the you must give the user a mechanism to invoke the method that<br />

displays the modal group. The following example provide a button:<br />

<br />

3. When the user clicks this button, the popup displays:<br />

Clicking OK on the popup dismisses it.<br />

294 <strong>Using</strong> <strong>Zen</strong>


The above example is similar to one available in the class ZENDemo.MethodTest in the SAMPLES<br />

namespace. You can try this sample from the <strong>Zen</strong> Demo main page by choosing Home, Overview,<br />

Methods, and Modal Group: MsgBox.<br />

15.1.4 The show Method<br />

show is a client-side JavaScript method that displays a modal group. It has no return value, and up to<br />

eight optional arguments. Previous topics have discussed some of these arguments. A complete list<br />

follows:<br />

• title — Title for the popup window. For static modal groups, this overrides the groupTitle value<br />

in the definition.<br />

• type — One of the following keywords:<br />

- "calendar" — Display the built-in calendar box.<br />

- "dynamic" — Display a dynamically created modal group.<br />

- "msgBox" — Display the built-in message box.<br />

- "static" — Display a statically defined .<br />

If no type argument is supplied, the default is "static" if a definition exists<br />

within the . Otherwise the default is "dynamic".<br />

• value — Value to display when a built-in modal group is used. When the type is:<br />

- "calendar" — value is a date in YYYY-MM-DD format. When the window pops up, the<br />

calendar displays this month and year with value as a pre-selected date.<br />

- "msgBox" — value is the HTML-formatted message content for the popup message.<br />

• top — Vertical coordinate at which the top left corner of the window will pop up (0 is the top)<br />

• left — Horizontal coordinate at which the top left corner of the window will pop up (0 is far left)<br />

• wid — Width of the popup window<br />

• hgt — Height of the popup window<br />

Modal Groups<br />

• parms — Object containing a set of additional characteristics passed on to the modalGroup as a<br />

set of name-value pairs. Typically this offers a way to pass additional parameters to the popup<br />

calendar.<br />

<strong>Using</strong> <strong>Zen</strong> 295


Popup Windows and Dialogs<br />

15.1.5 Attributes<br />

The component is the XML projection of the %ZEN.Component.modalGroup class.<br />

The following table lists the attributes that are available when defining a <br />

within a page class XData Contents definition.<br />

296 <strong>Using</strong> <strong>Zen</strong>


Modal Groups<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

groupTitle<br />

okCaption<br />

onaction<br />

Description<br />

has the same style and layout attributes as any <strong>Zen</strong><br />

group. The chapter <strong>Zen</strong> Layout describes them.<br />

Title to display at the top of the modal group. For static modal groups,<br />

you can set the groupTitle value in the definition. Otherwise,<br />

this value is set dynamically by the first argument of the show<br />

method.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

Caption displayed in OK button for a message box. The default is "OK".<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

Client-side JavaScript expression that runs whenever the user takes<br />

action on a built-in modal group popup ("msgBox" or "calendar").<br />

Generally this expression invokes a client-side JavaScript method<br />

defined in the page class. This method becomes the “onaction event<br />

handler” for the .<br />

When providing a value for an event handler attribute such as onaction,<br />

use double quotes to enclose the value and single quotes (if needed)<br />

within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

onhideGroup<br />

onshowGroup<br />

seed<br />

Client-side JavaScript expression that runs when the modal group is<br />

hidden.<br />

Client-side JavaScript expression that runs when the modal group is<br />

made visible.<br />

Allows you to pass some arbitrary value to the onaction event handler.<br />

%ZEN.Component.modalGroup also has a value property is used to hold a value for the modal group.<br />

value is set by the show method; applications should not set this. However, it is sometimes useful to<br />

retrieve this value, for example when working with the built-in calendar modal group.<br />

<strong>Using</strong> <strong>Zen</strong> 297


Popup Windows and Dialogs<br />

15.2 Popup Windows<br />

A popup window is a new browser window that pops up over the currently active window in response<br />

to a user event. The popup window becomes the active window as soon as it is displayed, and remains<br />

dominant until the user closes it.<br />

To display a popup window from a <strong>Zen</strong> page, do the following:<br />

1. Open the <strong>Zen</strong> page class in Studio.<br />

2. Add a client-side method that calls the function zenLaunchPopupWindow, for example:<br />

Method showPopupWindow() [ Language = javascript ]<br />

{<br />

zenLaunchPopupWindow(<br />

zenLink('MyApp.MyDialog.cls'),<br />

'A True Dialogue',<br />

'status,scrollbars,resizable,width=400,height=300');<br />

}<br />

zenLaunchPopupWindow has the following arguments:<br />

• A string that identifies the content you wish to display, either:<br />

- The name of a <strong>Zen</strong> page class, including its package name and .cls extension<br />

- The URI of the desired content<br />

The zenLink function makes sure that any additional URI parameters, such as session tracking<br />

values, are included in the link. You may use zenLink with the class name or with any URI.<br />

In the following example, the client-side method uses JavaScript string concatenation to<br />

construct a URI from several disparate elements before making the call to<br />

zenLaunchPopupWindow. The example also uses the escape function to correctly format<br />

any variable values used in the string:<br />

Method editCSSValue(context) [ Language = javascript ]<br />

{<br />

var ctrl = this.getComponentById('value');<br />

var value = ctrl.getValue();<br />

var url = zenLink('%ZEN.Dialog.cssDeclarationEditor.clscontext='<br />

+ escape(context) + '&declaration=' + escape(value)<br />

);<br />

zenLaunchPopupWindow(url,<br />

'CSSDeclarationEditor',<br />

'resizable,width=500,height=700'<br />

);<br />

}<br />

• A string that identifies the popup window<br />

• A comma-separated list of window attributes expected by the JavaScript function<br />

window_open.<br />

298 <strong>Using</strong> <strong>Zen</strong>


Dialogs<br />

3. Provide a component on the page that invokes this method, for example:<br />

<br />

4. Override the onPopupAction method to retrieve and use the value returned by the popup. Use<br />

the exact method signature shown below. Within the method, you may use the value in any way<br />

you wish, for example:<br />

Method onPopupAction(popupName, action, value) [ Language = javascript ]<br />

{<br />

var html = zenPage.getComponentById('mgHtml');<br />

html.setProperty('content','User entered: ' + value);<br />

}<br />

5. Clicking the button on the page displays the popup window.<br />

zenLaunchPopupWindow supports a fourth parameter, an array of values intended to be used as URI<br />

parameters. You can use it to supply parameters for the URI so that you do not have to worry about<br />

correctly concatenating them to the string provided in the first parameter. The convention for this array<br />

is as follows:<br />

var parms = new Object();<br />

parms.Aaa = 10;<br />

parms.Bbb = 20;<br />

Now when you call zenLaunchPopupWindow with parms as its fourth parameter, the function uses<br />

Aaa and Bbb as parameters within the URI that you provided in the first parameter, and gives these<br />

parameters the values that you assigned to the corresponding members of the parms array.<br />

zenLaunchPopupWindow takes care of all the details of correctly escaping these parameters in the<br />

URI string.<br />

Important:<br />

When Internet Explorer is the browser, do not use a submit operation to save values<br />

from any popup window. Use a save operation instead.<br />

15.3 Dialogs<br />

<strong>Zen</strong> includes some built-in classes designed to work as popup dialog windows. A <strong>Zen</strong> dialog window<br />

can contain any of the usual <strong>Zen</strong> components. All dialog windows are subclasses of<br />

%ZEN.Dialog.standardDialog, which is a <strong>Zen</strong> page class. This base class provides classic dialog buttons<br />

such as OK, Apply, and Cancel, as well as conventions for retrieving the values entered into the dialog<br />

if the user clicks OK.<br />

This topic describes the conventions for working with <strong>Zen</strong> dialog windows:<br />

• Displaying the built-in file select window<br />

<strong>Using</strong> <strong>Zen</strong> 299


Popup Windows and Dialogs<br />

• Displaying the built-in color select window<br />

• Creating a new dialog window based on %ZEN.Dialog.standardDialog<br />

• Creating a new dialog window template, as an alternative to %ZEN.Dialog.standardDialog<br />

15.3.1 File Selection Dialog Window<br />

The %ZEN.Dialog.fileSelect window displays and lets the user choose from a list of directories and<br />

files on the server system. The resulting value is a full path and filename. To display the fileSelect<br />

dialog as a popup window, use the steps in the previous topic, but in step 2, provide a client-side<br />

method similar to the following:<br />

Method showPopupFile() [ Language = javascript ]<br />

{<br />

var pathname = '\Temp';<br />

var showdir = '0';<br />

zenLaunchPopupWindow(<br />

'%ZEN.Dialog.fileSelect.clsDir=' + escape(pathname) +<br />

'&showdirectoryonly=' + showdir,<br />

'FileSelectWindow',<br />

'status,scrollbars,resizable,width=660,height=700');<br />

}<br />

The method calls the client-side function zenLaunchPopupWindow with these arguments:<br />

• URI string beginning with the filename of the %ZEN.Dialog.fileSelect class. The filename is all<br />

that is needed, but in this case, the URI continues with various parameters, including:<br />

- Pathname for the file search window. This is either a full pathname or a path relative to the<br />

Caché system management directory (\mgr under the Caché installation directory). If omitted,<br />

the default is the Caché system management directory.<br />

- A showdirectoryonly value of 0 so that files will be visible in the display. You can omit<br />

this, as 0 is the default. Set showdirectoryonly to 1 if you want to show directories only.<br />

• Identifier for the popup window<br />

• Comma-separated list of popup window characteristics<br />

15.3.2 Color Selection Dialog Window<br />

The %ZEN.Dialog.colorSelect window lets the user choose from a set of colored cells. The resulting<br />

value is an HTML color value, such as #F3FDDA. To display the fileSelect dialog as a popup window,<br />

use the steps in the previous topic, but in step 2, provide a client-side method similar to the following:<br />

300 <strong>Using</strong> <strong>Zen</strong>


Dialogs<br />

Method showPopupColor() [ Language = javascript ]<br />

{<br />

zenLaunchPopupWindow(<br />

'%ZEN.Dialog.colorSelect.cls',<br />

'ColorPicker',<br />

'status,scrollbars,resizable,width=500,height=700');}<br />

This method calls the client-side function zenLaunchPopupWindow with arguments as follows:<br />

• Filename of the %ZEN.Dialog.colorSelect class<br />

• Identifier for the popup window<br />

• Comma-separated list of popup window characteristics<br />

15.3.3 Creating a Dialog Window<br />

To create a new type of <strong>Zen</strong> dialog window based on %ZEN.Dialog.standardDialog:<br />

1. Subclass %ZEN.Dialog.standardDialog.<br />

2. Add a new XData block with:<br />

• The name dialogBody<br />

• A as the container<br />

• An id value for the component that you identify as the source of user input<br />

For example:<br />

XData dialogBody<br />

{<br />

<br />

<br />

<br />

<br />

}<br />

3. Override the server-side callback method %OnGetTitle, for example:<br />

Method %OnGetTitle() As %String<br />

{<br />

Quit $$$TextHTML("This is My Dialog")<br />

}<br />

4. Override the server-side callback method %OnGetSubtitle, for example:<br />

Method %OnGetSubtitle() As %String<br />

{<br />

Quit $$$TextHTML("by John Smith")<br />

}<br />

5. Override the client-side JavaScript method getDialogValue so that it returns a value, for example:<br />

<strong>Using</strong> <strong>Zen</strong> 301


Popup Windows and Dialogs<br />

Method getDialogValue() [ Language = javascript ]<br />

{<br />

return this.getComponentById('yourReply').getValue()<br />

}<br />

6. To give the dialog an Apply button (in addition to the automatic OK and Cancel buttons) override<br />

the APPLYBUTTON parameter and set it to 1:<br />

Parameter APPLYBUTTON = 1;<br />

7. To enable the $$$Text localization macros, give the DOMAIN parameter a meaningful value:<br />

Parameter DOMAIN = "MyDomain";<br />

8. When displayed, this dialog appears as follows:<br />

15.3.4 Creating a Dialog Window Template<br />

Suppose you want to apply your own styling to the dialogs, rather than using the same layout and<br />

graphics as in the <strong>Zen</strong> standard dialog. The most straightforward way to accomplish this is to create<br />

a new dialog window template class and use it as an alternative to %ZEN.Dialog.standardDialog in the<br />

above instructions. The steps are:<br />

1. Subclass %ZEN.Dialog.standardDialog.<br />

2. In your subclass, apply the style differences you require.<br />

3. When creating new dialogs, extend the new subclass instead of extending<br />

%ZEN.Dialog.standardDialog<br />

4. When you need a file selector class:<br />

302 <strong>Using</strong> <strong>Zen</strong>


Dialogs<br />

• Copy the class %ZEN.Dialog.fileSelect<br />

• Edit the copy so that it extends your new dialog window template class instead of extending<br />

%ZEN.Dialog.standardDialog<br />

5. When you need a color selector class:<br />

• Copy the class %ZEN.Dialog.colorSelect<br />

• Edit the copy so that it extends your new dialog window template class instead of extending<br />

%ZEN.Dialog.standardDialog<br />

<strong>Using</strong> <strong>Zen</strong> 303


16<br />

Other <strong>Zen</strong> Components<br />

This chapter describes components that fit into none of the previously defined categories: layout, tables,<br />

meters, charts, forms, controls, menus, or popups. These are the “other” components, in approximate<br />

order of complexity:<br />

• — A snippet of arbitrary HTML content<br />

• — A static image or other content within a frame<br />

• — A non-visible component that fires an event after a time interval<br />

• — A group component that helps visually organize a form<br />

• — A large, detailed palette from which the user can select colors<br />

• — Repeat the same layout for each entry returned by a runtime query.<br />

• — Draw an expandable tree of links based on a global or callback method.<br />

• — Display a view box based on data provided by a callback method.<br />

If you have examined the full roster of components, including those listed above, and still do not see<br />

the functionality you need, consider adding a custom component to the <strong>Zen</strong> library. The Custom<br />

Components chapter provides full instructions.<br />

16.1 HTML Content<br />

The <strong>Zen</strong> component provides a way to place arbitrary HTML content within a <strong>Zen</strong> page. The<br />

HTML content is displayed within the <strong>Zen</strong> page exactly as specified. This content is drawn within an<br />

enclosing HTML in the same manner as any other <strong>Zen</strong> component.<br />

There are several ways to define the content displayed by the element:<br />

<strong>Using</strong> <strong>Zen</strong> 305


Other <strong>Zen</strong> Components<br />

• Literally specify the content within the component:<br />

<br />

This is some HTML.<br />

<br />

The content must be well-formed. That is, any HTML elements within the content must have<br />

matching closing elements, and any attribute values must be quoted correctly. The tag<br />

is not allowed.<br />

The content may not reference other <strong>Zen</strong> components. However, it may contain <strong>Zen</strong> #()# expressions.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

• Define a server-side OnDrawContent callback method that writes HTML content. If you define<br />

such a method, and reference it from the element, this method is called whenever the<br />

component is displayed.<br />

<br />

The method itself would look something like this:<br />

Method GetHTMLContent(pSeed As %String) As %Status<br />

{<br />

&html<br />

Quit $$$OK<br />

}<br />

• If you work with the component programmatically, you will see that it has a content<br />

property, a string of HTML statements. An initial value of the content can be set by placing the<br />

desired HTML tags in between the and elements in XData Contents, or by referencing<br />

an OnDrawContent callback.<br />

Client code can change the value of the content property by resetting it from JavaScript. For<br />

example:<br />

// get html content<br />

var html = zenPage.getComponentById('myContent');<br />

html.setProperty('content','some new content');<br />

The component has the attributes listed in the following table.<br />

306 <strong>Using</strong> <strong>Zen</strong>


Framed Content<br />

Attribute<br />

<strong>Zen</strong> component<br />

attributes<br />

OnDrawContent<br />

seed<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong><br />

component.<br />

Optional.The name of a server-side callback method that provides<br />

HTML content for this component, either by using &html or by<br />

using the WRITE command.<br />

The OnDrawContent value must be the name of a server-only<br />

method defined in the page class whose XData Contents references<br />

this component, and it must return the %Status data type.<br />

Optional. Allows you to pass some arbitrary value to the<br />

OnDrawContent callback.<br />

16.2 Framed Content<br />

The <strong>Zen</strong> component is a wrapper for the HTML element. It may display images<br />

or other content within a frame. <strong>Zen</strong> has the following attributes.<br />

Attribute<br />

<strong>Zen</strong><br />

component<br />

attributes<br />

longdesc<br />

frameAlign<br />

frameBorder<br />

scrolling<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> component.<br />

URI that provides the link to the long (text) description of the frame.<br />

The align value for the HTML : "left", "right", or "center".<br />

The frameborder value for the HTML . If true, the frame has a<br />

border; if false it does not have a border.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has<br />

the value "true" or "false" in XData Contents, 1 or 0 in server-side code,<br />

true or false in client-side code. See Datatype Classes.<br />

The scrolling value for the HTML : "auto", "yes", or "no".<br />

<strong>Using</strong> <strong>Zen</strong> 307


Other <strong>Zen</strong> Components<br />

Attribute<br />

src<br />

Description<br />

Identifies the pathname and filename of the frame content. The path is<br />

relative to the Caché installation directory, for example:<br />

<br />

If you wish to change the contents of the frame from the client, you can<br />

do so programmatically by resetting the value of the src property of the<br />

iframe object.<br />

If you wish to place an image on a button control, so that you can define an onclick event or other<br />

types of event for it, use the control component. See the <strong>Zen</strong> Controls chapter.<br />

16.3 Page Timer<br />

The component has no visual representation. It raises a client-side event after a specified time<br />

period. You may place a on the <strong>Zen</strong> page within XData Contents as follows:<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<br />

<br />

}<br />

has the following attributes.<br />

308 <strong>Using</strong> <strong>Zen</strong>


Field Sets<br />

Attribute<br />

ontimeout<br />

Description<br />

Client-side JavaScript expression that runs whenever the timer runs out.<br />

Generally the ontimeout expression invokes a client-side JavaScript<br />

method defined in the page class. This method becomes the “ontimeout<br />

event handler” for the timer. It must accept an argument, timer, that represents<br />

this timer object.The element can use the built-in variable<br />

zenThis to pass the timer object to the method.<br />

When providing a value for this attribute, use double quotes to enclose<br />

the value and single quotes (if needed) within the JavaScript expression.<br />

For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

timeout<br />

Number of milliseconds in the timer. <strong>Zen</strong> automatically starts the timer<br />

when the page is first loaded. When the timeout time has elapsed, <strong>Zen</strong><br />

fires the ontimeout expression.<br />

The example above sets a timeout value of 10,000 milliseconds. This<br />

provides an timeout value of 10 seconds.<br />

The client-side ontimeout method might look something like the following. A only fires its<br />

ontimeout event once, so your JavaScript method must restart the timer (by calling its startTimer<br />

method) before exiting. The following example does this:<br />

Method timeout(timer) [ Language = javascript ]<br />

{<br />

// ...do something<br />

}<br />

// restart the timer<br />

timer.startTimer();<br />

16.4 Field Sets<br />

A is a group component that draws an outer box around the children and displays a title<br />

within this box. This creates a visual panel that can help to organize a page. The following example<br />

from the SAMPLES namespace class ZENApp.HelpDesk defines a panel called “Details” that contains<br />

a form with several different controls.<br />

<strong>Using</strong> <strong>Zen</strong> 309


Other <strong>Zen</strong> Components<br />

The that produces the above example looks like this:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

A group may contain a , as above, or a may contain a . A<br />

provides a visual grouping only; it is not a <strong>Zen</strong> form, because it does not provide any form<br />

behavior such as validation or submit. has the following attributes:<br />

310 <strong>Using</strong> <strong>Zen</strong>


Color Selector<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

legend<br />

title<br />

Description<br />

A has the same style and layout attributes as any <strong>Zen</strong> group.<br />

The chapter <strong>Zen</strong> Layout describes them.<br />

Text specifying the caption to display for this . The legend<br />

can be a literal string, or it can contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong><br />

Runtime Expressions.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

Text specifying a popup message to display for this . The title<br />

can be a literal string, or it can contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong><br />

Runtime Expressions.<br />

Although you enter ordinary text for this attribute, it has the underlying<br />

data type %ZEN.Datatype.caption. This makes it easy to localize its text<br />

into other languages. See <strong>Zen</strong> Localization.<br />

16.5 Color Selector<br />

The component lets the user view and select colors or enter RGB values in a large color<br />

palette. The palette is a grid that can be visualized as one possible slice from a three-dimensional cube<br />

of available colors. The captures a slice from the cube by accepting the user’s choice of<br />

one of three faces (red, green, or blue) and slicing through the cube, parallel to that face, at some saturation<br />

level (brighter or dimmer) to produce a grid of colors.<br />

From the user’s viewpoint, the has these features:<br />

• The user selects a color by clicking a square in the palette.<br />

• The user can cycle through different faces and slices of the color cube by clicking on the red,<br />

green, or blue color bars at left, bottom, and right. The segmented bar at left allows the user to<br />

select a slice that uses a brighter or dimmer range of color combinations.<br />

• The bar at top right displays the currently selected color and its corresponding HTML hexadecimal<br />

value. The user can copy (but not edit) the text value from this color bar.<br />

• At top left, the user can change the text entry fields R, G, and B to any number in the range 0–255,<br />

then click on the color bar at top right to apply these changes and see the result. The text fields R,<br />

G, and B also respond to user selections from the palette.<br />

<strong>Using</strong> <strong>Zen</strong> 311


Other <strong>Zen</strong> Components<br />

A with a color selected looks like this:<br />

has the following attributes. For a simpler color selection component, see .<br />

Attribute<br />

<strong>Zen</strong><br />

component<br />

attributes<br />

currCol<br />

currRow<br />

currSlice<br />

face<br />

Description<br />

has the same general-purpose attributes as any <strong>Zen</strong> component.<br />

The chapter <strong>Zen</strong> Style describes them.<br />

is not a full-blown control component, but it does allow the<br />

user to select a value, and it can be used within <strong>Zen</strong> forms. Any control<br />

attribute not listed in this table is not available for .<br />

0–based column number of the currently selected cell in the color palette.<br />

The default is 0. The range is from 0 to 15.<br />

0–based row number of the currently selected cell in the color palette. The<br />

default is 0. The range is from 0 to 15.<br />

0–based slice number of the currently selected slice of the 3–dimensional<br />

color cube. The default is 0. The range is from 0 to 15.<br />

Face number of the currently selected face of the 3–dimensional color cube:<br />

1, 2, or 3. The default is 1.<br />

312 <strong>Using</strong> <strong>Zen</strong>


Repeating Group<br />

Attribute<br />

onchange<br />

Description<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the value of the<br />

component changes. Generally this expression invokes a<br />

client-side JavaScript method. This becomes the “onchange handler” for<br />

the component.<br />

When providing a value for an event handler attribute such as onchange,<br />

use double quotes to enclose the value and single quotes (if needed) within<br />

the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See <strong>Zen</strong><br />

Runtime Expressions.<br />

ondblclick<br />

value<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />

double-clicks on the component.<br />

String that identifies the most recently selected HTML hexadecimal value.<br />

The default is:<br />

#FFFFFF<br />

16.6 Repeating Group<br />

A is a specialized group component that defines the layout for a single group entry,<br />

then outputs multiple entries with this layout. The number of entries, and the data contained in each<br />

entry, is determined by a runtime query.<br />

has the following attributes.<br />

<strong>Using</strong> <strong>Zen</strong> 313


Other <strong>Zen</strong> Components<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

Data source<br />

attributes<br />

Description<br />

has the same style and layout attributes as any<br />

<strong>Zen</strong> group.The chapter <strong>Zen</strong> Layout describes them.The default layout<br />

for a is vertical.<br />

has the same attributes as for specifying<br />

a data source. For details and examples, see the <strong>Zen</strong> Tables<br />

chapter as follows:<br />

• How to use query attributes with :<br />

- Data Sources (maxRows)<br />

- Specifying an SQL Query (sql)<br />

- Referencing a Class Query (queryClass, queryName)<br />

• How to provide elements within :<br />

- Query Parameters<br />

The typical layout strategy for a repeating group is for the element to enclose a<br />

horizontal group that contains the individual entry. Since the default layout for a <br />

is vertical, the result of this arrangement is that each entry is laid out horizontally, while the set of<br />

entries is laid out from top to bottom.<br />

The following excerpt from an XData Contents block provides an example of this layout strategy for<br />

. This is similar to the XData Contents block in the class ZENTest.RepeatingGroupTest<br />

in the SAMPLES namespace. Note the that defines the individual entry. This <br />

contains a and an component.<br />

314 <strong>Using</strong> <strong>Zen</strong>


Repeating Group<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

#(%query.Title)#<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

The following figure illustrates sample output from this excerpt. To produce this output, the user<br />

entered the key C, requested 10 rows, and then clicked Search. This caused <strong>Zen</strong> to display the repeating<br />

group using the first 10 entries that start with the letter C. The user then clicked an employee name in<br />

the group to display the alert window, which contains data retrieved from the server during the query.<br />

<strong>Using</strong> <strong>Zen</strong> 315


Other <strong>Zen</strong> Components<br />

16.7 Dynamic Tree<br />

The component displays a set of user-defined items as an expandable tree. In many ways<br />

is similar to . However, instead of specifying components, acquires<br />

its contents dynamically, using a global or callback.<br />

16.7.1 Defining a Tree <strong>Using</strong> a Global<br />

The simplest way to define a is to use a Caché global (multidimensional array). The following<br />

definition references the ^myTree global by providing the dataGlobal attribute:<br />

<br />

This definition causes the contents of the ^myTree global to be displayed on the page as nodes within<br />

an expandable tree.<br />

16.7.1.1 Node Labels<br />

Suppose you define ^myTree using the following statements at the Terminal command line:<br />

Set ^myTree("Root","Item 1") = "ZENMVC.MVCForm.cls"<br />

Set ^myTree("Root","Item 2") = "http://www.intersystems.com"<br />

Set ^myTree("Root","Item 2","SubItem") = "ZENDemo.Home.cls"<br />

Each global node now has one or more subscripts, such as "Root" or "Item 2". <strong>Zen</strong> uses these<br />

subscripts as labels for the nodes in the . Our ^myTree global can now generate a that looks like the following illustration. This is fully expanded, with the user<br />

holding the cursor over the node label "SubItem" at the lowest level.<br />

Important:<br />

When you use a global to define a , the resulting nodes always appear in<br />

alphabetical order (by label) because that is the way globals are organized in the<br />

database.<br />

16.7.1.2 Node Values<br />

When the user clicks on a node label such as:<br />

316 <strong>Using</strong> <strong>Zen</strong>


Dynamic Tree<br />

"SubItem"<br />

The corresponding node value is triggered. If the values are set as described in the previous topic, then<br />

this value is:<br />

"ZENDemo.Home.cls"<br />

Each node value is a string. Typically the node values are URI values. For example:<br />

• The name of a <strong>Zen</strong> page class:<br />

"ZENMVC.MVCForm.cls"<br />

• A Web site:<br />

"http://www.intersystems.com"<br />

• Or the URI of some other content.<br />

If you want a link to invoke JavaScript, you can start the URI with the string javascript: as in the<br />

following examples:<br />

• You can invoke a client-side JavaScript method in the page class:<br />

"javascript: zenPage.myMethod();"<br />

• Or simply execute a JavaScript expression:<br />

"javascript: alert('You clicked me!');"<br />

When providing a JavaScript expression, use double quotes to enclose the value and single quotes<br />

(if needed) inside the expression, as shown above.<br />

16.7.2 Defining a Tree <strong>Using</strong> a Callback<br />

can get its list of nodes by invoking a server-side callback method, defined in the page<br />

class. The method name is specified using the OnGetNodeInfo attribute. For example:<br />

<br />

<br />

<br />

<br />

This example defines a tree whose nodes are provided by the server-side callback method GetNodeInfo.<br />

When the user clicks on an item, the treeClick method is called. For a similar example, see the class<br />

ZENTest.DynaTreeTest in the SAMPLES namespace.<br />

<strong>Using</strong> <strong>Zen</strong> 317


Other <strong>Zen</strong> Components<br />

16.7.2.1 Callback Parameters<br />

A can contain zero or more elements. Each specifies an input<br />

parameter for the callback method that generates the . and both<br />

support this convention.<br />

Note:<br />

For examples, see ZENTest.DynaViewTest in the SAMPLES namespace.<br />

The element has the following attributes.<br />

Attribute<br />

paramName<br />

value<br />

Description<br />

The paramName must be unique within the . It becomes a<br />

subscript in the array of parameters passed to the callback method.<br />

The value supplied for a can be a literal string, or it can<br />

contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

16.7.2.2 Callback Method<br />

The OnGetNodeInfo attribute must identify a server-side callback method in the page class that contains<br />

the component. This callback is called repeatedly to get information about each node<br />

displayed within the tree. <strong>Zen</strong> handles this repetition as follows:<br />

• A tree contains a set of top-level nodes at level 1. A node may contain child nodes; each child is<br />

considered to have a level number one greater than its parent: 2, 3, 4, etc.<br />

• Starting with level 1, <strong>Zen</strong> calls the OnGetNodeInfo callback repeatedly until it returns false, indicating<br />

that there are no more nodes at the current level.<br />

• If a node reports that it has child nodes, <strong>Zen</strong> calls the OnGetNodeInfo callback repeatedly (with<br />

the appropriate value for pLevel) to get information on each child node until false is returned for<br />

that child level.<br />

The OnGetNodeInfo callback method must have a signature that looks like this:<br />

Method GetNodeInfo(Output tSC As %Status,<br />

ByRef pParams As %String,<br />

pLevel As %Integer,<br />

ByRef pHandle As %String,<br />

pNodeInfo As %ZEN.Auxiliary.NodeInfo) As %Boolean<br />

Where:<br />

• The method returns a %Boolean value indicating whether or not there is a node at the level indicated<br />

by pLevel.<br />

• tSC is a status code, returned by reference, that indicates success.<br />

318 <strong>Using</strong> <strong>Zen</strong>


• pParms represents any elements defined by the . pParms is an array.<br />

Each member of this array uses its paramName as a subscript and its value as a value.<br />

• pLevel is the current level of the tree.<br />

Dynamic Tree<br />

• pHandle is user-definable value that is passed, unchanged, to each call to the callback. The callback<br />

can use this store any state information it needs while providing the view information.<br />

• pNodeInfo is a pre-instantiated %ZEN.Auxiliary.NodeInfo object and is used to specify how the tree<br />

node should be displayed. A %ZEN.Auxiliary.NodeInfo object has the following properties.<br />

Property<br />

expanded<br />

hasChildren<br />

link<br />

Description<br />

If true, this node (if it has children) is initially displayed as expanded. If<br />

false, it is initially displayed as contracted. The default is true.<br />

expanded has the underlying data type %ZEN.Datatype.boolean. It has the<br />

value 1 or 0 in server-side code, true or false in client-side code. See<br />

Datatype Classes.<br />

If true, this node has one or more child nodes. If this is the case, thenthe<br />

next call to the OnGetNodeInfo callback will be to fetch information about<br />

these child nodes. The default is true.<br />

hasChildren has the underlying data type %ZEN.Datatype.boolean. It has the<br />

value 1 or 0 in server-side code, true or false in client-side code. See<br />

Datatype Classes.<br />

If non-empty, link defines a link that will be used if the user clicks on this<br />

node. This can be a URI such as the name of a page to display, or a<br />

JavaScript expression. If you want to invoke a client-side JavaScript<br />

method in the link, start the URI with javascript: as in:<br />

link="javascript:zenPage.myMethod();"<br />

When providing a JavaScript expression, use double quotes to enclose<br />

the value and single quotes (if needed) inside the expression.<br />

text<br />

value<br />

A string containing a value to display for this node within the tree.<br />

A string containing a logical value to associate with this node within the<br />

tree.<br />

<strong>Using</strong> <strong>Zen</strong> 319


Other <strong>Zen</strong> Components<br />

16.7.3 Attributes<br />

The component is the XML projection of the %ZEN.Component.dynaTree class. This<br />

topic has already described the dataGlobal and OnGetNodeInfo attributes in detail. The following<br />

table lists all the attributes.<br />

Attribute<br />

<strong>Zen</strong> group<br />

attributes<br />

childIndent<br />

dataGlobal<br />

Description<br />

has the same style and layout attributes as any <strong>Zen</strong><br />

group. The chapter <strong>Zen</strong> Layout describes them.<br />

HTML length value giving the amount by which each level within the<br />

dynaTree should be indented. The default is to use no indentation.<br />

Name of a Caché global (multidimensional array) that can provide<br />

the contents of the . This string must include the ^ prefix<br />

that is characteristic of Caché global names, for example:<br />

dataGlobal="^myTree"<br />

<strong>Using</strong> dataGlobal excludes OnGetNodeInfo. See Defining a Tree<br />

<strong>Using</strong> a Global.<br />

imageContracted<br />

(Optional) URI of the image to display when the is contracted.<br />

The user clicks on this image to expand the group. The<br />

default for imageContracted is the plus sign<br />

whose URI is:<br />

/csp/broker/images/contracted.gif<br />

You may specify an alternate image. The path that you provide for<br />

imageContracted must be relative to the Caché installation directory.<br />

imageExpanded<br />

(Optional) URI of the image to display when the is<br />

expanded. The user clicks on this image to contract the group. The<br />

default for imageExpanded is the minus sign<br />

whose URI is:<br />

/csp/broker/images/expanded.gif<br />

You may specify an alternate image. The path that you provide for<br />

imageExpanded must be relative to the Caché installation directory.<br />

320 <strong>Using</strong> <strong>Zen</strong>


Dynamic Tree<br />

Attribute<br />

onchange<br />

Description<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the current<br />

value of the changes. Generally this expression invokes<br />

a client-side JavaScript method.This method becomes the “onchange<br />

handler” for the .<br />

When providing a value for an event handler attribute such as<br />

onchange, use double quotes to enclose the value and single quotes<br />

(if needed) within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions. See<br />

<strong>Zen</strong> Runtime Expressions.<br />

onclick<br />

ondblclick<br />

OnGetNodeInfo<br />

selectedIndex<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />

clicks on a node within the .<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />

double-clicks on a node within the .<br />

Name of a server-side callback method that reports information about<br />

each node within the tree. <strong>Using</strong> OnGetNodeInfo excludes<br />

dataGlobal. See Defining a Tree <strong>Using</strong> a Callback.<br />

0-based index of the currently selected node in the .The<br />

default selectedIndex is –1 (nothing is selected).<br />

When you work with %ZEN.Component.dynaTree programmatically, you must also know about the<br />

following properties of the dynaTree class:<br />

• Each element provided in the original definition in XData Contents<br />

becomes a member of the dynaTree parameters property, a list collection of<br />

%ZEN.Auxiliary.parameter object. Each acquires an ordinal position in the parameters<br />

collection: 1, 2, 3, etc.<br />

• The read-only text property holds the text (display) value of the currently selected node within<br />

the tree. This is the node label that displays in the .<br />

• The read-only value property holds the logical (actual) value of the currently selected node within<br />

the tree. This is the string that is activated when the user clicks the corresponding label in the<br />

.<br />

<strong>Using</strong> <strong>Zen</strong> 321


Other <strong>Zen</strong> Components<br />

16.8 Dynamic View<br />

The component displays a set of user-defined items within a view box, similar to the<br />

way a file dialog box might display a set of files or directories. items can displayed in<br />

one of two modes:<br />

• "list" — All items are displayed compactly in a grid. Only the first column of data is displayed.<br />

• "details" — Each item is displayed as one row within a table. Each row may present several<br />

columns of data.<br />

A in “details” mode looks like the following example, based on the class<br />

ZENTest.DynaViewTest in the SAMPLES namespace.<br />

16.8.1 Defining a View <strong>Using</strong> a Callback<br />

gets its list of items by invoking a server-side callback method, defined in the page class.<br />

The method name is specified using the OnGetViewContents attribute. For example:<br />

<br />

<br />

<br />

This example defines a view box whose items are provided by the server-side callback method<br />

GetViewContents. When the user clicks on an item, the viewChange method is called. For a similar<br />

example, see the class ZENTest.DynaViewTest in the SAMPLES namespace.<br />

16.8.1.1 Callback Parameters<br />

A can contain zero or more elements. Each specifies an input<br />

parameter for the callback method that generates the . and both<br />

support this convention.<br />

322 <strong>Using</strong> <strong>Zen</strong>


Dynamic View<br />

Note:<br />

For examples, see ZENTest.DynaViewTest in the SAMPLES namespace.<br />

The element has the following attributes.<br />

Attribute<br />

paramName<br />

value<br />

Description<br />

The paramName must be unique within the . It becomes a<br />

subscript in the array of parameters passed to the callback method.<br />

The value supplied for a can be a literal string, or it can<br />

contain a <strong>Zen</strong> #()# expression. See <strong>Zen</strong> Runtime Expressions.<br />

16.8.1.2 Callback Method<br />

The OnGetViewContents attribute must identify a server-side callback method in the page class that<br />

contains the component. The callback method must have a signature that looks like this:<br />

Method GetViewContents(<br />

ByRef pParms As %String,<br />

Output pContents As %String,<br />

Output pHeaders As %String) As %Status<br />

Where:<br />

• The method returns a %Status value indicating success or failure.<br />

• pParms represents any elements defined by the . pParms is an array.<br />

Each member of this array uses its paramName as a subscript and its value as a value.<br />

• pContents is a multidimensional array that describes the set of items that will be displayed within<br />

the view box. The array is subscripted by item number (starting with 1). Each array element contains<br />

a $List structure containing the following information:<br />

Set pContents(n) =<br />

$ListBuild(textValue,logicalValue,icon,col2,col3,...))<br />

Where:<br />

- textValue is the value displayed for the item<br />

- logicalValue is a logical value associated with the item<br />

- icon is the URI of the image to be displayed with the item (if any)<br />

- Subsequent values define the values displayed in any additional columns when the dynaView<br />

is in “details” mode<br />

• pHeaders is a multidimensional array that provides a set of column headers, subscripted by column<br />

number. When the dynaView is in “details” mode, this is used to define how many columns of<br />

data to display and what the column headers are. For example:<br />

<strong>Using</strong> <strong>Zen</strong> 323


Other <strong>Zen</strong> Components<br />

// define 3 column headers<br />

Set pHeaders(1) = "Name"<br />

Set pHeaders(2) = "Size"<br />

Set pHeaders(3) = "Date"<br />

16.8.2 Attributes<br />

The component is the XML projection of the %ZEN.Component.dynaView class. This<br />

topic has already described the OnGetViewContents attribute in detail. The following table lists all the<br />

attributes.<br />

Property<br />

onchange<br />

Description<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the<br />

current value of the changes. Generally this<br />

expression invokes a client-side JavaScript method. This method<br />

becomes the “onchange handler” for the .<br />

When providing a value for an event handler attribute such as<br />

onchange, use double quotes to enclose the value and single<br />

quotes (if needed) within the JavaScript expression. For example:<br />

<br />

The JavaScript expression may contain <strong>Zen</strong> #()# expressions.<br />

See <strong>Zen</strong> Runtime Expressions.<br />

onclick<br />

ondblclick<br />

OnGetViewContents<br />

rows<br />

selectedIndex<br />

viewType<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />

clicks on a node within the .<br />

Client-side JavaScript expression that <strong>Zen</strong> invokes when the user<br />

double-clicks on a node within the .<br />

Name of a server-side callback method that provides the contents<br />

of the . See Defining a View <strong>Using</strong> a Callback.<br />

Number of rows to display when the is in list mode.<br />

0-based index of the currently selected node in the .<br />

The default selectedIndex is –1 (nothing is selected).<br />

Specifies how the contents of the should be displayed.<br />

Possible values are:<br />

• "list" — all items are displayed compactly in rows and columns<br />

• "details" — each item is displayed as one row within a table<br />

324 <strong>Using</strong> <strong>Zen</strong>


Dynamic View<br />

When you work with %ZEN.Component.dynaView programmatically, you must also know about the<br />

following properties of the dynaView class:<br />

• Each element provided in the original definition in XData Contents<br />

becomes a member of the dynaView parameters property, a list collection of<br />

%ZEN.Auxiliary.parameter object. Each acquires an ordinal position in the parameters<br />

collection: 1, 2, 3, etc.<br />

• The read-only text property holds the text (display) value of the currently selected node within<br />

the tree. This is the node label that displays in the .<br />

• The read-only value property holds the logical (actual) value of the currently selected node within<br />

the tree. This is the string that is activated when the user clicks the corresponding label in the<br />

.<br />

<strong>Using</strong> <strong>Zen</strong> 325


17<br />

Custom Components<br />

One of the most powerful features of the <strong>Zen</strong> framework is that it lets you easily develop new, reusable<br />

components that automatically work with other <strong>Zen</strong> components.<br />

The first chapter in this book, Introducing <strong>Zen</strong>, asserts that the <strong>Zen</strong> application development framework<br />

is extensible. The claim is certainly true. However, <strong>Zen</strong> anticipates many of the features that you might<br />

consider adding yourself. It is worthwhile to examine all of the available <strong>Zen</strong> components before<br />

beginning a custom development effort. Possibly, you will discover the features you want in a <strong>Zen</strong><br />

component that already exists.<br />

Following the introductory chapters <strong>Zen</strong> Component Concepts, <strong>Zen</strong> Layout, and <strong>Zen</strong> Style, this book<br />

presents the details of existing <strong>Zen</strong> components by category: tables, meters, charts, forms, controls,<br />

menus, popups, and other. After examining all of these chapters, you might find that you still wish to<br />

create custom components. If so, continue with this chapter to view the options and instructions for<br />

doing so.<br />

In general, the most common way to extend <strong>Zen</strong> is to create a custom component. Custom components<br />

fit into the existing <strong>Zen</strong> framework with minimal effort. They provide the style and behavior that you<br />

need while still obeying the <strong>Zen</strong> layout conventions and leveraging the <strong>Zen</strong> client/server framework.<br />

The following table describes options for creating custom components.<br />

<strong>Using</strong> <strong>Zen</strong> 327


Custom Components<br />

Options for Extending <strong>Zen</strong><br />

Task<br />

Build a composite<br />

component<br />

Modify component<br />

style<br />

Create a custom<br />

component<br />

Create a custom<br />

meter<br />

Description<br />

A composite arranges a group of existing, built-in <strong>Zen</strong><br />

components in a particular way.You can place this arrangement<br />

on the page as if it were a single component.<br />

You can make simple changes to the style of a built-in <strong>Zen</strong><br />

component by subclassing it and overriding its XData Style block.<br />

The chapter <strong>Zen</strong> Style, topic Overriding Built-in Styles explains<br />

how to do this.<br />

You can extend the roster of <strong>Zen</strong> components by writing a new<br />

component class. When you use <strong>Zen</strong> conventions to do this, the<br />

resulting class is automatically projected as XML for use in any<br />

<strong>Zen</strong> page XData Contents block.<br />

You can add a new type of meter to <strong>Zen</strong> by subclassing the base<br />

meter class and adding the method calls required to render the<br />

new meter’s SVG contents.<br />

17.1 Building Composite Components<br />

A composite component assembles a group of built-in <strong>Zen</strong> components and lets you refer to the group<br />

from XData Contents as if it were a single component. <strong>Zen</strong> places the children of the composite within<br />

the page’s object model as if XData Contents referenced them explicitly. This shorthand is convenient,<br />

and it also prevents errors when you want to repeat identical component arrangements on different<br />

pages.<br />

The following table is your checklist for building a composite component class. Not every item in the<br />

checklist is necessary for every composite. This checklist lists every possible item, and notes those<br />

that are optional. See the example of a composite component class that follows the table.<br />

Extending <strong>Zen</strong> with Composite Components<br />

Task<br />

Subclass<br />

Description<br />

Extend %ZEN.Component.composite to create a new class. The example<br />

creates a composite component class called myComposite in the MyApp<br />

package. Any class that extends %ZEN.Component.composite is a group,<br />

with all of the group layout and style attributes listed in the <strong>Zen</strong> Layout<br />

chapter.<br />

328 <strong>Using</strong> <strong>Zen</strong>


Building Composite Components<br />

Task<br />

Parameters<br />

Properties<br />

Methods<br />

XData<br />

Contents<br />

XML<br />

Element<br />

Description<br />

Provide class parameters and appropriate values. The NAMESPACE<br />

parameter is required to assign a namespace to the composite.You must<br />

reference this namespace when you place the composite component on<br />

a <strong>Zen</strong> page.<br />

(Optional) Provide properties, if needed. The example does not require<br />

any new properties for the subclass.<br />

(Optional) Provide supporting methods as needed for component behavior.<br />

The example provides an event handler method that is activated when<br />

the user clicks one of the buttons in the composite.<br />

Within the composite component class, define an XData Contents block<br />

that uses as its top-level element. The example provides<br />

two elements within .<br />

To add a composite element to a page, place its corresponding XML<br />

element in the page class XData Contents block.There is a specific syntax<br />

for this; see the example following this table.<br />

The following is a sample composite component class that provides two buttons:<br />

Class MyApp.myComposite Extends %ZEN.Component.composite<br />

{<br />

}<br />

/// Define xml namespace for this component<br />

Parameter NAMESPACE = "http://www.intersystems.com/myApp";<br />

/// Contents of this composite component:<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<br />

<br />

<br />

}<br />

Method okBtn() [Language = JavaScript]<br />

{<br />

alert('ok');<br />

}<br />

The correct way to reference this composite component from an XData Contents block is as follows:<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<br />

<br />

}<br />

<strong>Using</strong> <strong>Zen</strong> 329


Custom Components<br />

Where:<br />

• The element references the namespace defined for the composite component, and defines<br />

an alias for it, by providing the following attribute within the opening element:<br />

xmlns:myApp="http://www.intersystems.com/myApp"<br />

This statement defines an alias myApp for the namespace that was defined in the composite<br />

component class<br />

Parameter NAMESPACE = "http://www.intersystems.com/myApp";<br />

• The element references the myComposite component. This reference<br />

has the form:<br />

<br />

where alias is the namespace alias defined in the element (myApp in this case) and<br />

component is the name of the custom component class (myComposite in this case).<br />

17.1.1 The composite Property<br />

When you work with composite components programmatically, every component within a composite<br />

has a property called composite that points to the containing composite object. This makes it easy to<br />

define actions for a composite that refer to methods of the composite class. You can see this in the<br />

first element from the example above:<br />

<br />

The onclick attribute value for this definition uses zenThis.composite to represent the containing<br />

composite object. This convention allows the to call the okBtn method that is defined<br />

within the composite class.<br />

17.1.2 Composites and Panes<br />

To review panes and how their contents are defined, see the chapter <strong>Zen</strong> Layout.<br />

When a component is placed within a composite element, the contents of the pane can be<br />

defined within the composite class (or subclass of the composite). At runtime, the composite first looks<br />

for a pane with a given name within the current page; if it does not find it there, it looks within the<br />

composite class.<br />

330 <strong>Using</strong> <strong>Zen</strong>


17.2 Overriding Component Style<br />

Overriding Component Style<br />

If you have subclassed a built-in <strong>Zen</strong> component to modify styles already in use by a parent component,<br />

then the instructions in the chapter <strong>Zen</strong> Style, topic Overriding Built-in Styles, are sufficient. These<br />

are:<br />

1. Determine the relevant CSS style name<br />

2. Subclass the built-in <strong>Zen</strong> component<br />

3. Use the <strong>Zen</strong> Style Wizard to edit XData Style.<br />

If you want to define an entirely new CSS style (with a new name) and apply that style to a component,<br />

then there are additional steps to perform. You must not only define the CSS style, but also reference<br />

it from the class code that renders the custom component as HTML. At this point, you are truly creating<br />

a custom component. The next topic covers the necessary steps in detail.<br />

17.3 Creating Custom Components<br />

Each <strong>Zen</strong> component is implemented as a class and is completely self-contained. The component class<br />

specifies its own behavior (server and client methods) and appearance (SVG or HTML, DHTML, and<br />

stylesheets) in one logic unit: the class. Each component class has an XML projection. This projection<br />

consists of:<br />

• An XML element with the same name as the class (, , , etc.)<br />

• XML attributes, which are properties of that class (width, height, etc.)<br />

To build a <strong>Zen</strong> page you place a selection of the available XML elements and attributes in a wellformed<br />

XML document in the <strong>Zen</strong> page class. The container for this document is called XData Contents.<br />

At compile time, <strong>Zen</strong> generates the code required to display the page in the browser with the layout,<br />

style, and behavior that you have chosen for its components. At runtime, <strong>Zen</strong> handles all of the display<br />

details and correctly executes any snippets of JavaScript, HTML, or CSS that are embedded or referenced<br />

in the component or page classes.<br />

<strong>Zen</strong> components provide all of these features automatically because they inherit them from their base<br />

classes. This is something you can do yourself. To create a custom component, simply choose the<br />

appropriate base class and extend it. Your new class automatically gets the following features:<br />

• An XML projection to use in the page class XData Contents<br />

• Any properties, methods, parameters, or other characteristics of its parent(s)<br />

<strong>Using</strong> <strong>Zen</strong> 331


Custom Components<br />

• Appropriate handling of any client-side material in the class:<br />

- JavaScript<br />

- CSS style definitions<br />

- HTML<br />

- SVG<br />

• Properties can be exposed as settings, to be observed and modified using the client-side getProperty<br />

and setProperty methods.<br />

The following table is your checklist for creating a custom component class. The following topics<br />

describe each item in detail.<br />

Extending <strong>Zen</strong> with Custom Components<br />

Task<br />

Package<br />

XML Namespace<br />

Subclass<br />

Parameters<br />

XData Style<br />

Properties<br />

Methods<br />

%DrawHTML<br />

XML Element<br />

Description<br />

Use one class package for all your custom components.<br />

Use one XML namespace for all your custom components.<br />

Choose a base class from a short list of candidates.<br />

Provide class parameters, such as NAMESPACE.<br />

(Optional) Within the component class, provide an XData Style block<br />

that defines CSS styles.<br />

(Optional) Provide properties, if needed. The various properties of<br />

a component can be exposed as settings, and can be observed and<br />

modified using the client-side getProperty and setProperty<br />

methods.<br />

(Optional) Provide supporting methods as needed for component<br />

behavior.<br />

Within the component class, ensure that the %DrawHTML method<br />

references any new CSS styles. Visual components must draw the<br />

HTML (or SVG) needed to create their client-side visual<br />

representation.<br />

To add a custom component to a page, place its corresponding XML<br />

element in the page class XData Contents block. There is a specific<br />

syntax for this; see the Examples topic below.<br />

332 <strong>Using</strong> <strong>Zen</strong>


Creating Custom Components<br />

17.3.1 Package and Namespace<br />

The best practice is to use a common XML namespace for all your custom components (and only for<br />

custom components). Also, place all your component classes in their own package. There are two main<br />

reasons for these conventions:<br />

• Custom components need their own XML namespace to avoid conflict with other components.<br />

• The <strong>Zen</strong> framework automatically generates JavaScript and CSS stylesheet include files for your<br />

custom components. These files are generated on a per-class-package basis, so it is much easier<br />

to organize this if your custom components are contained within their own package.<br />

Whatever namespace you choose, it must specified by the NAMESPACE parameter within each custom<br />

component class that you create. For example:<br />

Parameter NAMESPACE = "http://www.mycompany.com/mycomponents";<br />

17.3.2 Base Class<br />

Choose a base class for the new component. There are five significant options to choose from. The<br />

following table and figure summarize the choices.<br />

Custom Component Base Classes<br />

Base Class<br />

%ZEN.Component.component<br />

%ZEN.Component.control<br />

%ZEN.SVGComponent.svgComponent<br />

%ZEN.SVGComponent.meter<br />

Purpose<br />

Visual, HTML based<br />

component.<br />

HTML based component<br />

can be placed within a<br />

form for the user to enter<br />

a value.<br />

Visual, SVG based<br />

component.<br />

Dynamically updated SVG<br />

graphic that displays a<br />

value.<br />

Inherited Attributes<br />

<strong>Zen</strong> components<br />

<strong>Zen</strong> components,<br />

<strong>Zen</strong> controls<br />

SVG components<br />

SVG components,<br />

meter components<br />

%ZEN.Component.object<br />

Non-visual component. Typically this is a helper<br />

object that is used by visual components and<br />

requires a client-side object representation.<br />

<strong>Using</strong> <strong>Zen</strong> 333


Custom Components<br />

Base Classes for Custom Components<br />

17.3.3 <strong>Zen</strong> Component Wizard<br />

Use the Caché Studio New <strong>Zen</strong> Component Wizard to create a new <strong>Zen</strong> component class. You can<br />

start the wizard using the Studio File New command, selecting the Custom tab, and clicking the New<br />

<strong>Zen</strong> Component icon.<br />

17.4 Custom Style<br />

To define a new CSS style for a custom component, you can place an XData Style block in the subclass.<br />

Within this block place a tag and a closing tag. Within<br />

the element, place whatever CSS style definitions you like.<br />

The built-in class %ZEN.Component.group includes the following XData Style block:<br />

334 <strong>Using</strong> <strong>Zen</strong>


Custom Style<br />

XData Style<br />

{<br />

<br />

/* @doc="Table used by groups." */<br />

table.group {<br />

padding: 0px;<br />

}<br />

/* @doc="Cell within table used by groups." */<br />

table.group td {<br />

padding: 0px;<br />

}<br />

/* @doc="Header within table used by groups." */<br />

table.group th {<br />

padding: 0px;<br />

}<br />

<br />

}<br />

Note the /* @doc="text" */ syntax in the above example. When you provide a comment for an<br />

XData Style entry using this syntax, the <strong>Zen</strong> Style Wizard automatically includes a description of your<br />

style in its list of available styles. To display this list while editing a <strong>Zen</strong> class in Studio, press CTRL-<br />

T to display the list of <strong>Zen</strong> templates. Select the <strong>Zen</strong> Style Wizard; a list of all defined styles appears.<br />

This list is organized alphabetically by component name.<br />

While viewing the list of styles in the <strong>Zen</strong> Style Wizard, you can select the radio button next to the<br />

name of the styles you want to edit and click OK. Templates for these styles appear in your XData<br />

Style block.<br />

Important:<br />

If you are overriding existing styles in a subclass of one of the built-in <strong>Zen</strong> components,<br />

the <strong>Zen</strong> Style Wizard offers the most convenient way to select the styles you want to<br />

override.<br />

The XData Style example above is a definition of styles for a built-in <strong>Zen</strong> component,<br />

%ZEN.Component.group. Suppose you wish to create a custom component with entirely new styles.<br />

In that case you will want to create styles named appropriately for your component. A component<br />

called MyComponent might include an XData Style block like the one shown below. <strong>Zen</strong> automatically<br />

includes this style definition in any page that uses in its XData Contents block:<br />

XData Style<br />

{<br />

<br />

/* @doc="Main style definition for MyComponent." */<br />

.MyComponent {<br />

color: blue;<br />

background: yellow;<br />

white-space: nowrap;<br />

}<br />

<br />

}<br />

Simply defining a XData Style block is not sufficient: the component class must actually use the newly<br />

defined CSS styles within the HTML that it generates. To accomplish this, you must provide a reference<br />

to the style in the %DrawHTML method that renders HTML for the custom component class. The<br />

<strong>Using</strong> <strong>Zen</strong> 335


Custom Components<br />

following sample %DrawHTML method references the MyComponent style defined in the XData<br />

Style example above:<br />

Method %DrawHTML()<br />

{<br />

&html<br />

}<br />

This sample %DrawHTML method uses a syntax that you see commonly throughout this book: &html<br />

followed by HTML statements enclosed in angle brackets . This is the ObjectScript syntax for<br />

embedded HTML statements. See the definition of the & symbol in the Caché ObjectScript Reference.<br />

By convention, any CSS style names you provide in an XData Style block should use a name that is<br />

related to the name of the component, as in the example above. This helps to avoid conflicts (which<br />

cannot be detected in advance due to the nature of CSS) and makes it easier for users to determine<br />

how to override styles. A component should never redefine a style defined by another component, or<br />

define an element-wide style selector (such as “input” or “table”), as this will cause interference with<br />

other components.<br />

Important:<br />

The chapter <strong>Zen</strong> Style, topic Cascade of Styles describes order of precedence rules<br />

for CSS styles defined in component, page, and application classes. Custom components<br />

are subject to these rules.<br />

17.4.1 XData SVGStyle<br />

XData Style does not apply to <strong>Zen</strong> SVG components. <strong>Zen</strong> SVG components use XData SVGStyle.<br />

To define styles for a custom <strong>Zen</strong> SVG component class, you can provide an XData SVGStyle block<br />

and add CSS statements between the tag and the closing <br />

tag. For example:<br />

XData SVGStyle<br />

{<br />

<br />

.customSVGComponent {<br />

fill: url(#myGrad);<br />

stroke: black;<br />

stroke-width: 2px;<br />

}<br />

<br />

}<br />

17.4.2 XData SVGDef<br />

The XData SVGStyle example above is from the class ZENTest.customSVGComponent in the SAMPLES<br />

namespace. It refers to a color myGrad as the fill color for the customSVGComponent shape.<br />

myGrad is defined in the same class, but in a separate block called XData SVGDef. This block defines<br />

myGrad as a shaded gradient from blue to red:<br />

336 <strong>Using</strong> <strong>Zen</strong>


Custom Properties<br />

XData SVGDef<br />

{<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

17.4.3 <strong>Zen</strong> Color Definitions<br />

The built-in class %ZEN.SVGComponent.svgPage provides an XData SVGDef block with several<br />

useful color definitions:<br />

• The glow-silver color produces a metallic look for instrumentation items such as the<br />

meter.<br />

• Meters such as the traffic light use glow-red, glow-yellow, and glow-green for indicator lamps.<br />

• Lamp colors glow-blue, glow-purple, glow-orange, and glow-teal are also available.<br />

always references this class, or some subclass of it, through its svgPage attribute, so these<br />

colors are always available to any SVG component.<br />

17.5 Custom Properties<br />

Since a component is a class, it may define properties in addition to those it inherits. The definition of<br />

these properties influence how they work on the server, how they can be used within the component’s<br />

corresponding JavaScript class definition, and how they can be specified within an XML representation<br />

of the page.<br />

17.5.1 Naming Conventions<br />

The chapter <strong>Zen</strong> Tutorial, topic <strong>Zen</strong> Naming Conventions, describes the case-sensitive naming conventions<br />

for properties in <strong>Zen</strong> classes. Briefly:<br />

• Client-only properties: myProperty<br />

• Server-only properties (the % is essential): %MyProperty<br />

• Properties that invoke an event handler via Javascript: onmousedown<br />

• Properties that identify a server-side callback method: OnCreateDataSet<br />

• Other properties: myProperty<br />

<strong>Using</strong> <strong>Zen</strong> 337


Custom Components<br />

17.5.2 XML Projection<br />

All <strong>Zen</strong> components are derived from the %XML.Adaptor class and use its mechanisms for defining<br />

their XML behavior. If you would like more detail about this, see the book <strong>Using</strong> XML with Caché,<br />

chapter Controlling the Caché Object-XML Projection.<br />

All simple properties of <strong>Zen</strong> components should have an XMLPROJECTION value of "attribute". If<br />

you do not want to make a property visible via XML, set its XMLPROJECTION parameter to "none"<br />

as in the following example:<br />

Property beeswax As %ZEN.Datatype.string(XMLPROJECTION="none");<br />

Datatypes from the %ZEN.Datatype package use a default XMLPROJECTION value of "attribute" so<br />

that they will be projected as XML attributes. <strong>Zen</strong> datatypes offer many conveniences when you are<br />

defining properties in a custom component class. See the topic Datatype Classes below.<br />

17.5.3 setProperty Method<br />

If you add a property to a custom component class, you must override the setProperty method in the<br />

subclass to implement cases for each property that you have added to the class. You can default to the<br />

superclass method for properties of the superclass. There are several examples of this practice in the<br />

topics below.<br />

Near the end of each example of a custom component class is a setProperty method that implements<br />

cases for properties defined in that class. See the Odometer Meter Example and the Clock Meter<br />

Example.<br />

17.5.4 Datatype Parameters<br />

All <strong>Zen</strong> classes inherit (from %ZEN.componentParameters) the following set of property parameters,<br />

which you can apply to any property you add to a <strong>Zen</strong> class. The property does not need to have a <strong>Zen</strong><br />

datatype to use these parameters:<br />

• ZENENCRYPT<br />

• ZENEXPRESSION<br />

• ZENLOCALIZE<br />

• ZENSETTING<br />

17.5.4.1 ZENENCRYPT<br />

Set ZENENCRYPT to 1 (true) to specify that a property’s value will be encrypted (using the current<br />

session key) when it is sent to the client. If this value is returned to the server, it will be automatically<br />

338 <strong>Using</strong> <strong>Zen</strong>


decrypted. This makes it possible to place sensitive data on the client for future processing on the<br />

server without letting a user view this data.<br />

The ZENENCRYPT parameter applies only to code that <strong>Zen</strong> generates from the XML description<br />

within XData Contents in the page class. If you bypass XData Contents and work with <strong>Zen</strong> pages<br />

programmatically, then you are responsible for handling the equivalent encryption tasks.<br />

17.5.4.2 ZENEXPRESSION<br />

Set ZENEXPRESSION to 1 (true) to indicate that the property can interpret a <strong>Zen</strong> #()# expression to<br />

get its value at runtime. For details, see <strong>Zen</strong> Runtime Expressions.<br />

17.5.4.3 ZENLOCALIZE<br />

Any <strong>Zen</strong> property that has its ZENLOCALIZE parameter set to 1 (true) automatically generates a<br />

Message Dictionary entry that can be used to translate the value of the property into another language.<br />

This is described in detail in the chapter <strong>Zen</strong> Localization.<br />

It is a good practice to localize any string-valued properties that contain messages that you want to<br />

display to communicate with the <strong>Zen</strong> application user. It is convenient to give a property the <strong>Zen</strong><br />

datatype %ZEN.Datatype.caption, which always has ZENLOCALIZE set to 1 (true) but you can set<br />

ZENLOCALIZE directly if you want to.<br />

The ZENLOCALIZE parameter:<br />

Custom Properties<br />

• Applies only if the class that uses it also defines a localization domain by providing a value for<br />

the DOMAIN class parameter.<br />

• Applies only to code that <strong>Zen</strong> generates from the XML description within XData Contents in the<br />

page class. If you bypass XData Contents and work with <strong>Zen</strong> pages programmatically, then you<br />

are responsible for handling the equivalent localization tasks (including calls to $$$Text). See<br />

<strong>Zen</strong> Localization.<br />

17.5.4.4 ZENSETTING<br />

Set ZENSETTING to 1 (true) to specify that the property should be considered as a “setting” within<br />

the client class definition. This means that:<br />

• The property becomes visible to <strong>Zen</strong> utilities such as the Control Test page<br />

• You can observe and modify its value using the client-side getProperty and setProperty methods<br />

Every datatype class in the %ZEN.Datatype package already sets ZENSETTING to 1. When you use<br />

the %ZEN.Datatype classes, you must set ZENSETTING to 0 for any properties that you do not want<br />

to be treated as settings.<br />

<strong>Using</strong> <strong>Zen</strong> 339


Custom Components<br />

17.5.5 Datatype Classes<br />

For convenience, <strong>Zen</strong> provides a set of datatype classes that you can use when defining properties in<br />

<strong>Zen</strong> classes. The datatype classes are in the %ZEN.Datatype package. The following table lists them.<br />

When you define new <strong>Zen</strong> classes, you are free to use any datatype classes you wish. <strong>Using</strong> the<br />

%ZEN.Datatype classes makes it easier to understand the purpose of a property in the context of a Web<br />

application. Also, in many cases datatype classes automatically enable features that you would otherwise<br />

have to encode yourself, including easy localization, event handler conventions, and language-independence<br />

for Boolean values and list arrays.<br />

Fundamentally, all <strong>Zen</strong> datatypes classes are strings. All of the datatypes listed in the following table<br />

share the same base class, %ZEN.Datatype.datatype, whose value is defined as type %Library.String.<br />

As you can see from the entries in the table, each of these strings is interpreted by its subclass in a<br />

uniquely useful way.<br />

Datatype Classes<br />

Class<br />

align<br />

boolean<br />

caption<br />

classMember<br />

className<br />

color<br />

cssClass<br />

Description<br />

HTML horizontal alignment value. Possible values for this are “left”, “right”,<br />

and “center”. For vertical alignment values, see valign.<br />

Boolean value: It can have the text value "true" or "false" in XData<br />

Contents. When accessed programmatically from ObjectScript or Basic<br />

code running on the server, it can have the value 1 or 0. When accessed<br />

programmatically from JavaScript code running on the client, it can have<br />

the value true or false.<br />

String that is automatically added to the set of localized text resources<br />

when this property is initialized by an XData Contents block provided that<br />

the page has defined a localization DOMAIN and its ZENLOCALIZE<br />

parameter is set to 1. See <strong>Zen</strong> Localization.<br />

Name of a server-side class member (such as a property name or method<br />

name). This class defines a datatype parameter, MEMBERNAME, that<br />

indicates the type of class member. When using this datatype to define<br />

a property, you must also provide a value for its MEMBERNAME<br />

parameter. Possible values for MEMBERNAME are “PROPERTY”,<br />

“METHOD”, “QUERY”, “INDEX”, or “XDATA”.<br />

Name of a server-side class.<br />

CSS color value.<br />

Name of a CSS style class.<br />

340 <strong>Using</strong> <strong>Zen</strong>


Custom Properties<br />

Class<br />

csv<br />

delegator<br />

eventHandler<br />

Description<br />

Comma-separated list of values such as “John,Paul,George,Ringo”<br />

Name of a server-side method within the current page class that is used<br />

as a callback method. For example, the <strong>Zen</strong> component has an<br />

OnDrawContent attribute that specifies the name of a server-side callback<br />

method that provides HTML content by using &html or by using the WRITE<br />

command. If defined, this callback is invoked on the server whenever this<br />

component is drawn. In the underlying class %ZEN.Component.html,<br />

OnDrawContent is defined to be of type delegator.<br />

JavaScript expression to be executed on the client in response to a clientside<br />

event. As an event handler, this JavaScript expression is expected<br />

to invoke a client-side method that is the “handler” for this event.<br />

For example, the <strong>Zen</strong> component has an onclick attribute that<br />

specifies what should happen when a user clicks on the control. In the<br />

underlying class %ZEN.Component.button, onclick is defined to be of type<br />

eventHandler.<br />

You must use the eventHandler type if you wish to use the %GetEventHandlers<br />

helper method to access the event handler from %DrawHTML.<br />

The next topic explains the details.<br />

expression<br />

float<br />

glvn<br />

html<br />

id<br />

integer<br />

length<br />

list<br />

name<br />

Server-side ObjectScript expression.<br />

Floating point numeric value.<br />

Name of a Caché global (multidimensional array) such as “^myGlobal”.<br />

String of text that is marked up using HTML.<br />

The id value for a component. It must not be used for any other purpose.<br />

Integer value.<br />

HTML length value. For example: “5” or “5%”.<br />

On the server a list represents a set of items as a piece-delimited string.<br />

On the client the list is converted to a JavaScript array. This datatype has<br />

a DELIMITER parameter, the value of which is used to delimit the server<br />

representation of the list. The default DELIMITER value is $C(5).<br />

The name value for a component. It must not be used for any other<br />

purpose.<br />

<strong>Using</strong> <strong>Zen</strong> 341


Custom Components<br />

Class<br />

resource<br />

script<br />

sql<br />

string<br />

style<br />

svgStyle<br />

uri<br />

valign<br />

value<br />

Description<br />

Name of a Caché resource. If you are not familiar with Caché resources,<br />

see the Caché Security Administration Guide chapter Assets and<br />

Resources.<br />

Client-side JavaScript expression.<br />

SQL statement. By default, properties of this type are encrypted when<br />

sent to the client (the ZENENCRYPT parameter is set to 1).<br />

String with a default MAXLEN of 250. You can reset the MAXLEN value.<br />

CSS style statement. For example: "color:red; background:<br />

yellow;"<br />

SVG CSS style definition. Styles within SVG are CSS compliant, but there<br />

is a different set of styles available, so this datatype designates them.<br />

URI value. For example: “http://www.intersystems.com/zen”<br />

HTML vertical alignment value. Possible values are “top”, “bottom”, and<br />

“middle”. For horizontal alignment values, see align.<br />

A value to be used as the value of an HTML control.<br />

17.6 Custom Methods<br />

Since a component is a class, it may define methods in addition to those it inherits. The definitions of<br />

these methods influence where and how they can be used. These rules are exactly the same for methods<br />

in <strong>Zen</strong> component classes as they are for methods within a <strong>Zen</strong> page.<br />

The chapter <strong>Zen</strong> Application Programming, topic <strong>Zen</strong> Page Methods, describes these rules. The following<br />

table summarizes them.<br />

342 <strong>Using</strong> <strong>Zen</strong>


Custom Methods<br />

Component Class Method Conventions<br />

Callable<br />

From<br />

Runs On<br />

Code<br />

Language<br />

Keyword<br />

Naming<br />

Convention<br />

Client<br />

Client<br />

JavaScript<br />

Language =<br />

JavaScript<br />

myMethod<br />

Client<br />

Server (but can<br />

send back code<br />

that runs on the<br />

client)<br />

ObjectScript or<br />

Basic<br />

<strong>Zen</strong>Method<br />

MyMethod<br />

Server<br />

Server<br />

ObjectScript or<br />

Basic<br />

—<br />

%MyMethod<br />

The most important method in your custom component class is the required server-side method<br />

%DrawHTML. The following topics describe how to work with this method.<br />

17.6.1 %DrawHTML<br />

The %DrawHTML method is responsible for providing the HTML used to draw a <strong>Zen</strong> component.<br />

This method is called when the page containing the component is first served. It may subsequently be<br />

called if the page needs to dynamically refresh the contents of the component, such as when the query<br />

for a is re-executed.<br />

The basic operation of the %DrawHTML method is very simple: Any output that this method produces<br />

is served up as HTML within the browser. You can output from %DrawHTML using the WRITE<br />

command, as follows:<br />

Method %DrawHTML()<br />

{<br />

Write "This is some HTML!",!<br />

}<br />

As an alternative to WRITE, you can use the ObjectScript syntax for embedded HTML statements.<br />

This syntax uses &html followed by HTML statements enclosed in angle brackets as in the following<br />

example:<br />

Method %DrawHTML()<br />

{<br />

&html<br />

}<br />

Any output from %DrawHTML is enveloped by the component’s enclosing element, as supplied<br />

by the <strong>Zen</strong> framework.<br />

What makes this convention powerful is that %DrawHTML is an instance method of the component<br />

class: it can execute logic and has access to the component’s properties and methods, as well as the<br />

<strong>Using</strong> <strong>Zen</strong> 343


Custom Components<br />

underlying Caché database. It supports Caché ObjectScript expression, CSP #()# syntax, and <strong>Zen</strong> #()#<br />

expression syntax. The following simple example uses a number of these features:<br />

Method %DrawHTML()<br />

{<br />

#; draw items as specified by myCount<br />

For i=1:1:..myCount {<br />

&html<br />

}<br />

}<br />

17.6.2 Helper Methods for %DrawHTML<br />

The <strong>Zen</strong> framework defines three server-side helper methods for use in the %DrawHTML method<br />

for custom components: %MakeId, %Attr, and %GetEventHandlers. The class code for <br />

shows one way to use these methods effectively in %DrawHTML:<br />

344 <strong>Using</strong> <strong>Zen</strong>


Custom Methods<br />

Class %ZEN.Component.button Extends control<br />

{<br />

Parameter DEFAULTCONTROLCLASS = "button";<br />

/// Caption displayed for this button.<br />

/// This is a localized value.<br />

Property caption As %ZEN.Datatype.caption;<br />

/// defines style sheet used by this component<br />

XData Style<br />

{<br />

<br />

/* @doc="Style for button (input)." */<br />

.button {<br />

}<br />

<br />

}<br />

Method %DrawHTML()<br />

{<br />

Set disabled = $S(..disabled:"disabled",1:"")<br />

Set tIgnore("onchange") = ""<br />

&html<<br />

<br />

><br />

}<br />

/// This method fills in reasonable default values for<br />

/// this control. Used by tools (such as Control Tester) to<br />

/// dynamically create controls.<br />

Method %SetDefaultValues()<br />

{<br />

Set ..caption = "Button"<br />

}<br />

/// Set the value of a named property.<br />

Method setProperty(property, value, value2) [ Language = javascript ]<br />

{<br />

switch(property) {<br />

}<br />

}<br />

case 'caption':<br />

this.caption = value;<br />

var el = this.findElement('control');<br />

if (el) {<br />

el.value = this.caption;<br />

}<br />

break;<br />

case 'value':<br />

// do not set control value; just internal value<br />

this.value = value;<br />

break;<br />

default:<br />

// dispatch<br />

return this.invokeSuper('setProperty',arguments);<br />

}<br />

return true;<br />

Important:<br />

This example is close, but not identical, to the built-in class %ZEN.Component.button.<br />

The following topics discuss how each of the %DrawHTML helper methods is used:<br />

<strong>Using</strong> <strong>Zen</strong> 345


Custom Components<br />

• %MakeId — Generate the id value for the HTML element that displays the component on the<br />

page. Use a consistent naming scheme so that the client-side method findElement can find the<br />

HTML element on the page.<br />

• %Attr — Assign a value to an attribute of the HTML element that displays the component on the<br />

page. This method may be called repeatedly to assign values to all the HTML attributes required<br />

to render the component.<br />

• %GetEventHandlers — Retrieve all of the event handling information from the component definition,<br />

so that the HTML representation of the component can correctly match each user event<br />

with the code that should execute.<br />

17.6.3 Identifying HTML Elements<br />

The %MakeId server-side method ensures uniqueness for the id of every HTML element on the output<br />

page. The example in the previous topic calls %MakeId from embedded HTML to set the id for the<br />

HTML element as follows:<br />

id="#(..%MakeId("control"))#"<br />

%MakeId concatenates the string provided by the caller with the underscore character “_” followed<br />

by the unique sequential number that <strong>Zen</strong> assigns to every component it places on the page. It then<br />

gives this identifier to <strong>Zen</strong> to use as the value for the id attribute in the enclosing for the element.<br />

Additionally, if the component is part of a repeating group, <strong>Zen</strong> adds a further underscore character<br />

“_” followed by the tuple number.<br />

Thus, if you view the source of any generated <strong>Zen</strong> page you will see enclosing elements with<br />

generated id values like spacer_23 in the following example:<br />

<br />

The following more complex excerpt shows how <strong>Zen</strong> provides unique HTML id values for each element<br />

in a repeating group of radio buttons. This excerpt is part of the page that results when <strong>Zen</strong> renders<br />

the class ZENDemo.FormDemo from the SAMPLES namespace:<br />

346 <strong>Using</strong> <strong>Zen</strong>


<br />

Marital Status:<br />

<br />

<br />

<br />

<br />

Single&nbsp;<br />

<br />

<br />

Married&nbsp;<br />

<br />

<br />

Divorced&nbsp;<br />

<br />

<br />

Widowed&nbsp;<br />

<br />

<br />

Other&nbsp;<br />

<br />

<br />

<br />

The client-side equivalent for %MakeId is a JavaScript method called makeId. The custom meter<br />

component examples use makeId. See the Odometer Meter Example and the Clock Meter Example.<br />

17.6.4 Finding HTML Elements<br />

Custom Methods<br />

When you are writing client-side code and need to access a specific HTML element on the page, you<br />

can use the findElement method. Its argument is the value that you assigned to the id attribute when<br />

placing the component on the page. findElement combines this string with the sequential identifier<br />

for the element on the output page to generate the appropriate HTML id for the element on the output<br />

page. It uses this information to obtain a pointer to the component object within the page object model<br />

for the rendered page, then returns that pointer so that you can use properties and methods of the<br />

component object.<br />

Ordinary <strong>Zen</strong> components inherit findElement from %ZEN.Component.object. For SVG components<br />

you must use findSVGElement from %ZEN.SVGComponent.svgComponent. The custom meter<br />

component examples use findSVGElement.<br />

findElement and findSVGElement work correctly only if you have assigned HTML id values using<br />

%MakeId (on the server) or makeId (on the client).<br />

<strong>Using</strong> <strong>Zen</strong> 347


Custom Components<br />

17.6.5 Setting HTML Attribute Values<br />

The %Attr server-side method assigns a value to an attribute of the HTML element that displays the<br />

component on the page. This method may be called repeatedly to assign values to all the HTML<br />

attributes required to render the component. The following sample %DrawHTML method uses %Attr<br />

in rendering the component:<br />

Method %DrawHTML()<br />

{<br />

Set disabled = $S(..disabled:"disabled",1:"")<br />

Set tIgnore("onchange") = ""<br />

&html<br />

}<br />

Suppose the value of the controlStyle attribute is currently myActionStyle. As the<br />

%DrawHTML method outputs HTML, an expression in this format:<br />

#(..%Attr("style",..controlStyle))#<br />

Generates the following output:<br />

style="myActionStyle"<br />

17.6.6 Attaching Event Handlers to HTML Elements<br />

The %GetEventHandlers server-side method gets all the event handler attributes for a given component<br />

and uses them to write out any event handler attributes for the HTML that displays that component in<br />

the output page.<br />

Important:<br />

%GetEventHandlers can only find event handler attributes whose underlying property<br />

has been defined using the datatype class %ZEN.Datatype.eventHandler.<br />

The chapter <strong>Zen</strong> Controls, topic Control Attributes lists the event handler attributes that you can<br />

specify for a control component on a <strong>Zen</strong> form. The types of events covered by this list include mouse<br />

movements, mouse clicks, or key clicks. Other types of <strong>Zen</strong> component have event handlers, but controls<br />

offer the single largest pool for comparison.<br />

Preceding chapters have explained that to set up an event handler for a built-in <strong>Zen</strong> component you<br />

must specify a JavaScript expression as the value of the corresponding event handler attribute. Generally<br />

this JavaScript expression invokes a client-side method that serves as the “handler” for this event. Of<br />

course, if you set up the component this way you must also write the client-side method that is being<br />

invoked.<br />

348 <strong>Using</strong> <strong>Zen</strong>


For custom components, you must take additional steps to connect each user event with its appropriate<br />

handler. This connection takes place in the %DrawHTML method for the custom component. Consider<br />

the %DrawHTML method for the component:<br />

Method %DrawHTML()<br />

{<br />

#; handle onclick directly<br />

Set tIgnore("onclick")=""<br />

Set tIgnore("onchange")=""<br />

#; select image to display<br />

Set tSrc = ..src<br />

If (..streamId '= "") {<br />

Set tSrc = ##class(%CSP.Page).Link(<br />

"%25CSP.StreamServer.clsSTREAMOID="_$ZCVT(..streamId,"O","URL"))<br />

}<br />

Custom Methods<br />

#; disabled logic<br />

Set tSrc = $Case(..disabled,0:tSrc,:$S(..srcDisabled="":tSrc,1:..srcDisabled))<br />

}<br />

&html<br />

In the above example, some interesting things take place with regard to event handlers. The following<br />

line tells %GetEventHandlers to ignore any value provided for the onchange event handler, even if<br />

it discovers that there is such a value:<br />

Set tIgnore("onchange") = ""<br />

You must provide one such line for each event handler that you want to handle directly in<br />

%DrawHTML, as shown for onclick and onchange in the example above. Then, at the end of<br />

%DrawHTML, pass the variable tIgnore to %GetEventHandlers by reference, as shown in the<br />

example:<br />

#(..%GetEventHandlers(.tIgnore))#<br />

The %DrawHTML example above asks %GetEventHandlers to ignore onclick and onchange, but<br />

for different reasons in each case: ignores onchange because it does not accept user input.<br />

ignores onclick because it is designed to handle all onclick events in the same way, without<br />

permitting the <strong>Zen</strong> programmer to specify a different behavior in the page class. Therefore, it provides<br />

code in %DrawHTML to handle this event directly. Any event handlers that are not expressly ignored<br />

by %DrawHTML in this way are written out to the page exactly as defined by the <strong>Zen</strong> programmer.<br />

Now consider this expression from the example above:<br />

#($S(..onclick="":"",1:"class=""imageLink"""))#<br />

This expression uses the ObjectScript $SELECT function to return the first true expression it<br />

encounters in a list of expressions. Looking at the expressions provided: If the component’s<br />

<strong>Using</strong> <strong>Zen</strong> 349


Custom Components<br />

onclick attribute value is an empty string, this statement writes an empty string. Otherwise, this statement<br />

formats the HTML element on the output page by writing out the following string:<br />

class="imageLink"<br />

The following expression directs the client-side HTML page to invoke the component’s imageClick<br />

method in response to any user mouse clicks on the corresponding HTML element.<br />

onclick="zenPage.getComponent(#(..index)#).imageClick();"<br />

The imageClick method is a client-side JavaScript method in the component class. It uses<br />

the JavaScript helper method zenInvokeCallbackMethod to invoke onclick callback method for this<br />

component. The imageClick method looks like this:<br />

Method imageClick() [ Language = javascript ]<br />

{<br />

if (!this.disabled) {<br />

// invoke callback, if present<br />

zenInvokeCallbackMethod(this.onclick,this,'onclick');<br />

}<br />

}<br />

Where the zenInvokeCallbackMethod arguments are as follows:<br />

• this.onclick — The component’s onclick attribute value (a JavaScript expression that invokes<br />

a client-side JavaScript method)<br />

• this — A pointer to the component object<br />

• 'onclick' — The HTML name for the event (must be quoted)<br />

This completes the connection between the HTML element, the event, and its handler. You must provide<br />

similar conventions for any event that you intend your custom component to support.<br />

17.6.7 HTML for Dynamic Components<br />

%DrawHTML works differently for components that change in response to runtime information or<br />

that are generated using SVG.<br />

The is an example of a component that writes no static HTML at all. Its %DrawHTML<br />

method simply sets the values of properties such as the currently selected month and date, in preparation<br />

for the more complex JavaScript method renderContents that is invoked whenever the page needs<br />

to redraw the calendar. renderContents and its helper methods generate an array of dynamic HTML<br />

statements based on the user’s current selections of calendar month and date. For details, examine the<br />

class code for %ZEN.Component.calendar.<br />

350 <strong>Using</strong> <strong>Zen</strong>


Examples of Custom Components<br />

17.7 Examples of Custom Components<br />

The following is an example of a custom component that defines a title bar. This example is from the<br />

ZENDemo package in the SAMPLES namespace:<br />

Class ZENDemo.Component.demoTitle Extends %ZEN.Component.component<br />

{<br />

/// XML namespace for this component.<br />

Parameter NAMESPACE = "http://www.intersystems.com/zendemo";<br />

/// Domain used for localization.<br />

Parameter DOMAIN = "ZENDemo";<br />

/// Title displayed within this pane.<br />

Property title As %ZEN.Datatype.caption;<br />

/// Category displayed within this pane (above the title).<br />

Property category As %ZEN.Datatype.caption<br />

[ InitialExpression = {$$$Text("ZEN Demonstration")} ];<br />

/// defines style sheet used by this component<br />

XData Style<br />

{<br />

<br />

.demoTitle {<br />

color: black;<br />

background: #c5d6d6;<br />

width: 100%;<br />

padding: 0px;<br />

border-bottom: 1px solid darkblue;<br />

font-size: 1.4em;<br />

font-family: verdana;<br />

text-align: center;<br />

}<br />

<br />

}<br />

/// Draw the HTML contents of this component.<br />

Method %DrawHTML()<br />

{<br />

Set tCategory = ..category<br />

}<br />

}<br />

&html<br />

The purpose of defining a custom component for a title bar is to provide a consistent look for every<br />

page in a Web application. Page classes in the ZENDemo package provide countless examples of the<br />

<strong>Using</strong> <strong>Zen</strong> 351


Custom Components<br />

correct way to reference a custom component. An XData Contents block that provides a correct reference<br />

looks like this:<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<br />

<br />

<br />

}<br />

Where:<br />

• The element references the namespace defined for the custom component, and defines an<br />

alias for it, by providing the following attribute within the opening element:<br />

xmlns:demo="http://www.intersystems.com/zendemo"<br />

This statement defines an alias demo for the full namespace name.<br />

• The element references the demoTitle custom component. This reference has<br />

the form:<br />

<br />

where alias is the namespace alias defined in the element (demo in this case) and component<br />

is the name of the custom component class (demoTitle in this case).<br />

There are further examples of custom components, and references to these components, in the SAMPLES<br />

namespace. You can examine these classes in Studio. The examples of custom component classes<br />

include:<br />

• ZENDemo.Component.demoMenu, a subclass of %ZEN.Component.composite<br />

• ZENDemo.Component.sidebar, a subclass of %ZEN.Component.component<br />

• ZENDemo.Component.bullet, a subclass of %ZEN.Component.object<br />

• ZENTest.customComponent, a subclass of %ZEN.Component.control<br />

• ZENTest.customSVGComponent, a subclass of %ZEN.SVGComponent.svgComponent<br />

352 <strong>Using</strong> <strong>Zen</strong>


Creating Custom Meters<br />

17.8 Creating Custom Meters<br />

The following table is your checklist for building a custom meter component. Also see the odometer<br />

and clock examples that follow the table.<br />

Extending <strong>Zen</strong> with Custom Meters<br />

Task<br />

Subclass<br />

renderMeter<br />

Parameters<br />

Properties<br />

XData SVGStyle<br />

XData SVGDef<br />

setProperty<br />

Methods<br />

renderLabel<br />

XML Element<br />

Description<br />

Extend %ZEN.SVGComponent.meter to create a new class.<br />

Any subclass of %ZEN.SVGComponent.meter must override this<br />

method to render the SVG contents of the meter. The odometer<br />

and clock examples show how to make SVG calls from the meter<br />

class.<br />

(Optional) Provide class parameters and appropriate values. The<br />

odometer example overrides the DEFAULTHEIGHT and<br />

DEFAULTVIEWBOXHEIGHT parameters from the base meter<br />

class.<br />

(Optional) Provide properties, if needed. The odometer sets a<br />

maximum number of digits for its display. The clock overrides the<br />

value property from the base meter class with an ObjectScript<br />

expression that is evaluated each time the meter is displayed. For<br />

the clock, this expression calculates the current time.<br />

(Optional) Provide any CSS style definitions for the meter.<br />

(Optional) Provide any SVG definitions for the meter.<br />

(Optional) You may override this method to provide unique ways<br />

to set certain properties of the meter. The clock example does this<br />

for the value property, then defers to the superclass for setting all<br />

other properties.<br />

(Optional) Provide supporting methods as needed for component<br />

behavior.<br />

(Optional) Any subclass of %ZEN.SVGComponent.meter may override<br />

this method to set the x and y positions of the meter label.<br />

To add the component to a page, place it within that page’s XData<br />

Contents block as an XML element. Examples of this convention<br />

follow this table.<br />

<strong>Using</strong> <strong>Zen</strong> 353


Custom Components<br />

17.8.1 Custom Meters in XData Contents<br />

The following sample XData Contents block refers to two custom meter elements, a clock called<br />

and an odometer called :<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

17.8.2 Odometer Meter Example<br />

The class code to display the meter would look like the following example:<br />

354 <strong>Using</strong> <strong>Zen</strong>


Creating Custom Meters<br />

Class MyTest.svgOdoDisplay Extends %ZEN.SVGComponent.meter<br />

{<br />

/// Default height of this component.<br />

Parameter DEFAULTHEIGHT As INTEGER = 40;<br />

/// Default viewBoxHeight of this component.<br />

/// This is set to 25 to provide a fixed coordinate system for meters.<br />

Parameter DEFAULTVIEWBOXHEIGHT As INTEGER = 40;<br />

/// maximum digits to display<br />

Property maxDigits As %ZEN.Datatype.length [ InitialExpression = 5 ];<br />

/// Render the inner SVG contents of this component.<br />

/// This is implemented by subclasses.<br />

Method renderMeter() [ Language = javascript ]<br />

{<br />

var digits=this.maxDigits<br />

var width=digits*5+8<br />

// body<br />

var body=this.document.createElementNS(SVGNS,'rect');<br />

body.setAttribute('class','speedometer-body');<br />

body.setAttribute('fill','url(#speedometer-bodyGrad)');<br />

body.setAttribute('x',5);<br />

body.setAttribute('y',3);<br />

body.setAttribute('width',90);<br />

body.setAttribute('height',14);<br />

body.setAttribute('rx',2);<br />

body.setAttribute('filter','url(#dropShadow)');<br />

}<br />

this.svgGroup.appendChild(body);<br />

var box=this.document.createElementNS(SVGNS,'rect');<br />

box.setAttribute('class','speedometer-levelTextBox');<br />

box.setAttribute('fill','url(#speedometer-bodyGrad2)');<br />

box.setAttribute('x',48-(width/2));<br />

box.setAttribute('y',5);<br />

box.setAttribute('width',width+3);<br />

box.setAttribute('height',10);<br />

box.setAttribute('rx',1);<br />

this.svgGroup.appendChild(box);<br />

var off=51+(width/2)<br />

var lvlText = this.document.createElementNS(SVGNS,'text');<br />

lvlText.setAttribute('id',this.makeId('levelText'));<br />

lvlText.setAttribute('class','speedometer-levelText');<br />

lvlText.setAttribute('x',off);<br />

lvlText.setAttribute('y',13);<br />

lvlText.setAttribute('text-anchor','end');<br />

var textNode = this.document.createTextNode(this.value);<br />

lvlText.appendChild(textNode);<br />

this.svgGroup.appendChild(lvlText);<br />

// label<br />

this.renderLabel('50%',32);<br />

Method setProperty(property, value) [ Language = javascript ]<br />

{<br />

switch(property) {<br />

case 'value':<br />

var text = this.findSVGElement('levelText');<br />

var lvl = value<br />

this.odometerValue = value;<br />

if (!(isNaN(value))) {<br />

lvl = value * this.scaleFactor;<br />

<strong>Using</strong> <strong>Zen</strong> 355


Custom Components<br />

}<br />

}<br />

// update odometer text<br />

text.setAttribute("class",<br />

(lvl>=0) "speedometer-levelText" : "speedometer-levelTextNeg");<br />

}<br />

this.setTextNode("levelText",lvl);<br />

break;<br />

default:<br />

return this.invokeSuper('setProperty',arguments);<br />

}<br />

return true;<br />

17.8.3 Clock Meter Example<br />

The class code to display the meter would look like the following example:<br />

356 <strong>Using</strong> <strong>Zen</strong>


Creating Custom Meters<br />

Class MyTest.svgWatch Extends %ZEN.SVGComponent.meter<br />

{<br />

/// Speed adjustment default = 1<br />

Property speed As %ZEN.Datatype.integer [ InitialExpression = 1 ];<br />

/// Steps the second hand runs default=1 :== 1/10 sec<br />

Property steps As %ZEN.Datatype.integer [ InitialExpression = 1 ];<br />

/// Text for logo displayed in center<br />

Property logo As %ZEN.Datatype.caption [ InitialExpression = "<strong>Zen</strong>" ];<br />

/// Current value of the meter.<br />

/// Start time in seconds since midnight [0...84000]<br />

Property value As %ZEN.Datatype.string [ InitialExpression = {$p($h,",",2)} ];<br />

/// fixed offset to local time in seconds e.g. -3600 => 1 hour less<br />

Property timeshift As %ZEN.Datatype.integer [ InitialExpression = 0 ];<br />

Method renderMeter() [ Language = javascript ]<br />

{<br />

var now = new Date();<br />

this._starttime=now.getTime();<br />

this._startvalue=this.value;<br />

var value=this.value*1+this.timeshift*1;<br />

var h=value/3600*30+90;<br />

var m=(value%3600)/60*6+90 ;<br />

var s=(value%60)*6+90 ;<br />

//<br />

var body=this.document.createElementNS(SVGNS,'g');<br />

body.setAttribute('class','Watch-shadow');<br />

body.setAttribute('fill','none');<br />

body.setAttribute('stroke','none');<br />

body.setAttribute('stroke-width','2px');<br />

body.setAttribute('filter','url(#dropShadow)');<br />

this.svgGroup.appendChild(body);<br />

//<br />

var path1d='M 20,45 a30,30 0 1,1 0,0.001'<br />

//<br />

var q1=this.document.createElementNS(SVGNS,'g');<br />

q1.setAttribute('id',this.makeId('quarter'));<br />

q1.setAttribute('fill','yellow');<br />

q1.setAttribute('stroke','yellow');<br />

body.setAttribute('stroke-width',2);<br />

body.appendChild(q1);<br />

for (a=0;a


Custom Components<br />

hr.setAttribute('fill','lightgrey');<br />

hr.setAttribute('stroke','grey');<br />

hr.setAttribute('stroke-width',1);<br />

hr.setAttribute('transform','rotate('+h+',50,45)');<br />

body.appendChild(hr);<br />

//<br />

var c=this.document.createElementNS(SVGNS,'path');<br />

c.setAttribute('d','M 25,45 l 27,-3 5,3 -5,3 z');<br />

hr.appendChild(c);<br />

// <br />

hr=this.document.createElementNS(SVGNS,'g');<br />

hr.setAttribute('id',this.makeId('min'));<br />

hr.setAttribute('fill','lightgrey');<br />

hr.setAttribute('stroke','grey');<br />

hr.setAttribute('stroke-width',2);<br />

hr.setAttribute('transform','rotate('+m+',50,45)');<br />

body.appendChild(hr);<br />

//<br />

c=this.document.createElementNS(SVGNS,'path');<br />

c.setAttribute('d','M 22,45 l 40,0');<br />

hr.appendChild(c);<br />

//<br />

c=this.document.createElementNS(SVGNS,'path');<br />

c.setAttribute('d','M 20,45 l 7,-1.5 0,3 z');<br />

c.setAttribute('stroke-width',1);<br />

hr.appendChild(c);<br />

// <br />

var c=this.document.createElementNS(SVGNS,'circle');<br />

c.setAttribute('cx',50);<br />

c.setAttribute('cy',45);<br />

c.setAttribute('r',3);<br />

c.setAttribute('fill','red');<br />

c.setAttribute('stroke-width',1);<br />

c.setAttribute('stroke','grey');<br />

body.appendChild(c);<br />

//<br />

hr=this.document.createElementNS(SVGNS,'g');<br />

hr.setAttribute('id',this.makeId('sec'));<br />

hr.setAttribute('fill','lightgrey');<br />

hr.setAttribute('stroke','red');<br />

hr.setAttribute('stroke-width',1);<br />

hr.setAttribute('transform','rotate('+s+',50,45)');<br />

body.appendChild(hr);<br />

//<br />

c=this.document.createElementNS(SVGNS,'path');<br />

//c.setAttribute('d','M 0,-12.5 l 0,50');<br />

c.setAttribute('d','M 50,45 l 7.5,0 -50,0');<br />

hr.appendChild(c);<br />

// <br />

var c=this.document.createElementNS(SVGNS,'circle');<br />

c.setAttribute('cx',50);<br />

c.setAttribute('cy',45);<br />

c.setAttribute('r',1);<br />

c.setAttribute('fill','black');<br />

c.setAttribute('stroke-width',1);<br />

c.setAttribute('stroke','black');<br />

body.appendChild(c);<br />

// logo<br />

var logo = this.document.createElementNS(SVGNS,'text');<br />

logo.setAttribute('id',this.makeId('logo'));<br />

logo.setAttribute('class','speedometer-logoText');<br />

logo.setAttribute('x',50);<br />

logo.setAttribute('y',35);<br />

logo.setAttribute('text-anchor','middle');<br />

358 <strong>Using</strong> <strong>Zen</strong>


Creating Custom Meters<br />

var textNode = this.document.createTextNode(this.logo);<br />

logo.appendChild(textNode);<br />

this.svgGroup.appendChild(logo);<br />

// label<br />

this.renderLabel('50%','97.5%');<br />

this.updateHandles();<br />

}<br />

/// Internal method: update position of needle<br />

Method updateHandles() [ Language = javascript ]<br />

{<br />

if (this.animate)<br />

}<br />

{<br />

}<br />

delete this._timerId;<br />

var now = new Date();<br />

var time=now.getTime();<br />

var delta=(time-this._starttime)/1000; //only seconds<br />

//if (delta >= (1/60)) // 0.1° change<br />

//{<br />

var value=this._startvalue*1+delta;<br />

this.setProperty('value',value);<br />

//}<br />

this._timerId = window.setTimeout('zenPage.getComponent(' + this.index<br />

+ ').updateHandles()',this.steps*100);<br />

Method setProperty(property, value) [ Language = javascript ]<br />

{<br />

switch(property) {<br />

case 'value':<br />

this.value=value;<br />

value+=this.timeshift*1;<br />

// calculate actual rotation<br />

var h = (value/120)+90;<br />

var m = (value%3600)/10+90;<br />

var s = (value%60)*6+90;<br />

this.findSVGElement('hour').setAttribute('transform','rotate('+h+',50,45)');<br />

this.findSVGElement('min').setAttribute('transform','rotate('+m+',50,45)');<br />

this.findSVGElement('sec').setAttribute('transform','rotate('+s+',50,45)');<br />

;break<br />

}<br />

}<br />

case 'logo':<br />

this.logo = value;<br />

this.setTextNode('logo',this.logo);<br />

break;<br />

default:<br />

return this.invokeSuper('setProperty',arguments);<br />

}<br />

return true;<br />

<strong>Using</strong> <strong>Zen</strong> 359


18<br />

<strong>Zen</strong> Application Programming<br />

A <strong>Zen</strong> application specifies the full set of activities that can result when a <strong>Zen</strong> client and server interact.<br />

These activities may consist of displaying Web pages, issuing queries to a database, writing data to<br />

disk, and more. When you create a <strong>Zen</strong> application, you create a suite of <strong>Zen</strong> classes that specify these<br />

activities. The language you use for these classes is Caché ObjectScript — with embedded snippets<br />

of XML, HTML, SVG, and JavaScript as needed.<br />

For an introduction to <strong>Zen</strong> application programming, see these chapters:<br />

• Introducing <strong>Zen</strong><br />

• <strong>Zen</strong> Tutorial<br />

• <strong>Zen</strong> Client and Server<br />

• <strong>Zen</strong> Application Concepts<br />

This chapter provides reference details that build upon the foundation provided by these chapters.<br />

18.1 <strong>Zen</strong> Classes as CSP Classes<br />

The base application class %ZEN.application and the base page class %ZEN.Component.page each<br />

inherit from %CSP.page. This means that every <strong>Zen</strong> application class and every <strong>Zen</strong> page class is also<br />

an instantiable Caché Server Page. All the CSP page class properties, methods, parameters, and variables<br />

(such as %session) are available to <strong>Zen</strong> application and page classes.<br />

The introductory chapter <strong>Zen</strong> Client and Server explains the relationship between <strong>Zen</strong> and CSP. This<br />

chapter provides reference details for the <strong>Zen</strong> side of this relationship. The book <strong>Using</strong> Caché Server<br />

Pages (CSP) provides details for CSP.<br />

<strong>Using</strong> <strong>Zen</strong> 361


<strong>Zen</strong> Application Programming<br />

18.2 <strong>Zen</strong> Application Classes<br />

Every <strong>Zen</strong> application has an application class. This is a class derived from %ZEN.application that<br />

provides high-level housekeeping and acts as the single root for all of the pages in the application. The<br />

application does not keep an inventory of its pages. The association between the application and its<br />

pages occurs because every <strong>Zen</strong> page class identifies the application that it belongs to.<br />

The following table lists the elements of a <strong>Zen</strong> application class.<br />

Application Class Elements<br />

Element<br />

APPLICATIONNAME<br />

CSSINCLUDES<br />

HOMEPAGE<br />

JSINCLUDES<br />

USERPACKAGES<br />

USERSVGPACKAGES<br />

Role<br />

Class<br />

parameter<br />

Class<br />

parameter<br />

Class<br />

parameter<br />

Class<br />

parameter<br />

Class<br />

parameter<br />

Class<br />

parameter<br />

Purpose<br />

Defines a text string that you can use in titles or<br />

labels.<br />

Comma-separated list of cascading style sheet<br />

(CSS) files to include for every page in the<br />

application. See <strong>Zen</strong> Style.<br />

URI of a default Home Page for the application.<br />

This makes it possible for the application class to<br />

be specified as a starting point for the application,<br />

even though it does not itself display a page.<br />

When the application class receives an HTTP<br />

request, it redirects the request to the URI specified<br />

by the HOMEPAGE class parameter.<br />

Comma-separated list of JavaScript include files<br />

to include for every page in the application.<br />

Comma-separated list of user-defined class<br />

packages whose HTML class and style definitions<br />

are in pre-generated include files. These include<br />

files will be available to every page within the<br />

application.<br />

Comma-separated list of user-defined class<br />

packages whose SVG class and style definitions<br />

are in pre-generated include files. These include<br />

files will be available to every page within the<br />

application.<br />

362 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Page Classes<br />

Element<br />

XData Style<br />

Role<br />

Embedded<br />

XML<br />

document<br />

Purpose<br />

Any CSS style definitions that appear within this<br />

XData block are placed on every page within the<br />

application. See <strong>Zen</strong> Style.<br />

When programming, be aware that the application class can contain server-side methods written in<br />

Caché Basic or ObjectScript only. It cannot contain any client-side methods marked with the JavaScript<br />

keyword, or client/server methods marked with the <strong>Zen</strong>Method keywords. The application class can<br />

execute methods on the server only.<br />

18.3 <strong>Zen</strong> Page Classes<br />

Pages within a <strong>Zen</strong> application are derived from the class %ZEN.Component.page. A page class defines<br />

and serves the contents of a <strong>Zen</strong> page in a browser. For an introduction to <strong>Zen</strong> pages, see these chapters:<br />

• <strong>Zen</strong> Tutorial<br />

• <strong>Zen</strong> Client and Server<br />

• <strong>Zen</strong> Application Concepts<br />

For details about placing components on a <strong>Zen</strong> page, see:<br />

• <strong>Zen</strong> Component Concepts<br />

• <strong>Zen</strong> Layout<br />

• <strong>Zen</strong> Style<br />

This topic provides reference details to support these chapters.<br />

18.3.1 <strong>Zen</strong> Page Parameters<br />

There are a number of class parameters that a page class can use to control the behavior of the page.<br />

The following table lists the most useful of them. Others are described in the online class documentation.<br />

<strong>Using</strong> <strong>Zen</strong> 363


<strong>Zen</strong> Application Programming<br />

Page Class Parameters<br />

Parameter<br />

APPLICATION<br />

AUTOLOGOUT<br />

CSSINCLUDES<br />

DOMAIN<br />

JSINCLUDES<br />

PAGENAME<br />

PAGETITLE<br />

RESOURCE<br />

USERPACKAGES<br />

USERSVGPACKAGES<br />

Description<br />

Package and class name of the associated application.<br />

If 1 (true) attempt to refresh this page when its session has<br />

expired. If 0 (false) do not. The default is 1.<br />

Comma-separated list of cascading style sheet (CSS) include<br />

files. See <strong>Zen</strong> Style.<br />

Used for <strong>Zen</strong> Localization. The default is "" (an empty string<br />

indicating no domain).<br />

Comma-separated list of JavaScript include files for the page.<br />

Defines a text string that you can use in titles or labels. If not<br />

specified, the <strong>Zen</strong> page class name is used.<br />

Default value for the component’s title attribute.<br />

Name of a system Resource for which the current user must<br />

hold USE privileges in order to view this page or to invoke any<br />

of its server-side methods from the client.<br />

See the Caché Security Administration Guide, chapter Assets<br />

and Resources, topic Application Resources and Their Privileges.<br />

Comma-separated list of user-defined class packages whose<br />

HTML class and style definitions are in pre-generated include<br />

files.<br />

Comma-separated list of user-defined class packages whose<br />

SVG class and style definitions are in pre-generated include<br />

files.<br />

18.3.2 <strong>Zen</strong> Special Variables<br />

<strong>Zen</strong> offers several special variables to represent instantiated objects of various types within the <strong>Zen</strong><br />

application. These variables offer a convenient way to reference the methods and properties of these<br />

objects from within <strong>Zen</strong> page or <strong>Zen</strong> component class code.<br />

364 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Page Classes<br />

Special Variables on the Server Side<br />

Server Side<br />

Variable<br />

Refers To<br />

Use in<br />

These<br />

Classes<br />

Use in <strong>Zen</strong><br />

Runtime<br />

Expressions<br />

%application<br />

Application object<br />

Page<br />

No<br />

%composite<br />

Current composite object (if any)<br />

Page,<br />

Component<br />

Yes<br />

%page<br />

Current page object<br />

Page,<br />

Component<br />

Yes<br />

%query<br />

Current ResultSet object (if any)<br />

Page,<br />

Component<br />

Yes<br />

%session<br />

Current CSP session object<br />

Page,<br />

Component<br />

Yes<br />

%this<br />

Current object (page or component)<br />

Page,<br />

Component<br />

Yes<br />

%url<br />

An object whose properties are URI<br />

parameters of the current page<br />

Page,<br />

Component<br />

Yes<br />

%zenContext<br />

String that indicates what the server<br />

code is currently doing<br />

Page<br />

No<br />

Note that the %url special variable will only contain values when a page is first served; If you refer<br />

to %url in subsequent methods calls or component refreshes, its properties will have no value. If you<br />

need to refer to a value passed in via a URI parameter, define a property of your page class, link it to<br />

a URI parameter using the ZENURL parameter, and then refer to this value via the %page object. See<br />

<strong>Zen</strong> Page URI Parameters, later in this chapter.<br />

18.3.2.1 %application<br />

The server-side %application variable is available in every <strong>Zen</strong> page class. It is intended for use<br />

in methods that run while the page object is being created. It refers to the instance, on the server, of<br />

the application class that is associated with this page. This allows the page to invoke server-side<br />

methods defined in the application class.<br />

For example, the following method is defined in the application class ZENDemo.Application in the<br />

SAMPLES namespace:<br />

<strong>Using</strong> <strong>Zen</strong> 365


<strong>Zen</strong> Application Programming<br />

ClassMethod GetQuickLinks(Output pLinks) As %Status<br />

{<br />

Set pLinks("Home") = "ZENDemo.Home.cls"<br />

Set pLinks("Expense Calculator") = "ZENDemo.ExpenseCalculator.cls"<br />

Set pLinks("MVC Master Detail") = "ZENMVC.MVCMasterDetail.cls"<br />

Set pLinks("MVC Chart") = "ZENMVC.MVCChart.cls"<br />

Set pLinks("MVC Meters") = "ZENMVC.MVCMeters.cls"<br />

Set pLinks("MVC Form") = "ZENMVC.MVCForm.cls"<br />

Set pLinks("Test Suite") = "ZENTest.HomePage.cls"<br />

Set pLinks("Controls") = "ZENDemo.ControlTest.cls"<br />

Set pLinks("Methods") = "ZENDemo.MethodTest.cls"<br />

Quit $$$OK<br />

}<br />

Page classes that are associated with this application can then invoke this method as follows:<br />

Class ZENDemo.ExpenseCalculator Extends %ZEN.Component.page<br />

{<br />

/// Application this page belongs to.<br />

Parameter APPLICATION = "ZENDemo.Application";<br />

}<br />

// ...Intervening lines removed...<br />

/// Return an array of quick links to be displayed by the locator bar.<br />

ClassMethod GetQuickLinks(Output pLinks) As %Status<br />

{<br />

// dispatch to our application class<br />

Quit %application.GetQuickLinks(.pLinks)<br />

}<br />

There is no client-side equivalent for %application.<br />

18.3.2.2 %page and zenPage<br />

<strong>Zen</strong> offers special variables to represent the <strong>Zen</strong> page object on the client and server sides:<br />

• In ObjectScript or Basic code that runs on the server side, the page object is %page:<br />

Set btn = %page.%GetComponentById("NewBtn1")<br />

• In <strong>Zen</strong> runtime expressions, the page object is %page:<br />

text id="rows" label="Rows:" value="#(%page.Rows)#" size="5"/><br />

• In JavaScript methods that run on the client side, the page object is zenPage:<br />

var chart = zenPage.getComponentById('chart');<br />

• In JavaScript expressions that are values of XML attributes, the page object is zenPage:<br />

<br />

18.3.2.3 %this, this, and zenThis<br />

<strong>Zen</strong> offers special variables to represent a <strong>Zen</strong> object (component or page) on the client and server<br />

sides:<br />

366 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Page Classes<br />

• In ObjectScript or Basic code that runs on the server side, the object itself is %this:<br />

Set %this.Name = pSource.Name<br />

• In <strong>Zen</strong> runtime expressions, the object itself is %this:<br />

Item #(%this.tuple)#: #(%query.Title)#<br />

• In JavaScript methods that run on the client side, the object itself is this:<br />

var out = this.getComponentById('events');<br />

• In JavaScript expressions that are values of XML attributes, the object itself is zenThis:<br />

onchange="zenPage.changeLayout('svgFrame',zenThis.getValue());"<br />

18.3.2.4 zenEvent<br />

Suppose you have a JavaScript expression as the value of an XML event handler attribute, such as<br />

onchange in the following example:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

The zenEvent special variable refers to the current JavaScript Event object that describes the event.<br />

zenEvent provides a browser-neutral way to get access to the current event (such as a mouse click).<br />

In the example above, onchange references the notifyOnChange method. The client-side method<br />

notifyOnChange can reference the zenEvent special variable inside its JavaScript code.<br />

zenEvent only works inside client-side JavaScript methods that are referenced from XML event<br />

handler attributes, as is the case for , onchange, and notifyOnChange above.<br />

18.3.2.5 %zenContext<br />

When any activity on the server is being initiated by <strong>Zen</strong>, the server-side special variable %zenContext<br />

tells you which type of activity it is. %zenContext is a string. If %zenContext has the value:<br />

• page, <strong>Zen</strong> is serving the page in response to an HTTP request<br />

• submit, <strong>Zen</strong> is processing a submit request<br />

• method, <strong>Zen</strong> is processing a hyperevent<br />

Sometimes it is possible to have trouble with code being executed at compile time. To detect this,<br />

check for:<br />

<strong>Using</strong> <strong>Zen</strong> 367


<strong>Zen</strong> Application Programming<br />

$G(%zenContent)==""<br />

There is no client-side equivalent for %zenContext.<br />

18.3.3 <strong>Zen</strong> Runtime Expressions<br />

Rather than always providing static information in a <strong>Zen</strong> page description, sometimes it is useful for<br />

the page running on the client to be able to invoke runtime expressions that execute on the server. For<br />

example, perhaps the caption text for a button needs to be different depending on the identity of the<br />

currently logged-in user, which can only be determined from the server at runtime. Various runtime<br />

values can play a part in these decisions. For this reason, <strong>Zen</strong> provides a way for client-side application<br />

code to contain expressions that are resolved only on the server, and only at runtime.<br />

Important:<br />

The syntax rules for <strong>Zen</strong> runtime expressions are extremely specific.<br />

A runtime expression is enclosed within #()# and looks something like this:<br />

<br />

Where myProperty has a specific value on the server at runtime.<br />

<strong>Zen</strong> runtime expression syntax can be used, with restrictions, in the following contexts only:<br />

• XML that is embedded within an XData block (certain XML elements and attributes only)<br />

• A server-side Caché ObjectScript method or <strong>Zen</strong>Method (but not a JavaScript method)<br />

• JavaScript that is embedded within a &js block in a <strong>Zen</strong>Method<br />

• A JavaScript expression provided as the value of an XML attribute such as onclick<br />

• HTML that is embedded within an &html block in a server-side method<br />

The following items cannot appear within the #()# delimiters of a <strong>Zen</strong> runtime expression:<br />

• Calls to macros, such as $$$Text<br />

• JavaScript expressions<br />

• ObjectScript expressions, unless the runtime expression appears inside a server-side ObjectScript<br />

method or <strong>Zen</strong>Method, as shown later in this topic<br />

18.3.3.1 Runtime Expressions in XML<br />

<strong>Zen</strong> runtime expressions can be used within a <strong>Zen</strong> class XData block, but only the values of specific<br />

XML elements and attributes can contain <strong>Zen</strong> runtime expressions. One such example is the <br />

caption attribute:<br />

<br />

368 <strong>Using</strong> <strong>Zen</strong>


Of all the possible attributes, only caption, value, and hidden support <strong>Zen</strong> runtime expressions.<br />

The value of onclick in the above example does contain a <strong>Zen</strong> runtime expression, but this is acceptable<br />

because the value of onclick is a JavaScript expression, which may contain #()# syntax. Refer to the<br />

restrictions listed in the topic above.<br />

XML elements and attributes that support <strong>Zen</strong> runtime expressions are clearly identified throughout<br />

this book; you may find them by searching for the #()# string in the book text.<br />

Another way to tell that an XML attribute supports runtime expressions is to consult the Caché class<br />

documentation to see if the corresponding property has the datatype parameter ZENEXPRESSION<br />

set to 1 (true).<br />

You cannot simply set a property to have ZENEXPRESSION=1 to cause the property to support runtime<br />

expressions. Built-in <strong>Zen</strong> component classes provide ZENEXPRESSION=1 to indicate that the property<br />

supports runtime expressions, not to enable it to do so.<br />

On the other hand, when you create your own component subclasses as instructed in the Custom<br />

Components chapter, Datatype Parameters topic, you can set ZENEXPRESSION=1 for properties in<br />

those subclasses. It must be a property of a custom component class and not a property of one of the<br />

built-in <strong>Zen</strong> component classes.<br />

A significant number of XML attributes support <strong>Zen</strong> runtime expressions, but only one XML element<br />

supports them. This is the component, which may contain literal text and #()# runtime<br />

expressions. For example:<br />

Item #(%this.tuple)#: #(%query.Title)#<br />

18.3.3.2 Runtime Expressions and Special Variables<br />

A runtime expression may use the server-side special variables listed in the topic <strong>Zen</strong> Special Variables,<br />

above. <strong>Zen</strong> runtime expressions support the following server-side special variables only:<br />

• %composite<br />

• %page<br />

• %query<br />

• %session<br />

• %this<br />

• %url<br />

<strong>Zen</strong> Page Classes<br />

By limiting expressions to a pre-defined set of object property values, the page developer maintains<br />

control over which server-side values the client can see. Otherwise it would be possible for a page to<br />

execute code that the page developer did not intend, and thus present a security risk.<br />

<strong>Using</strong> <strong>Zen</strong> 369


<strong>Zen</strong> Application Programming<br />

18.3.3.3 Runtime Expressions in Server-Side Methods<br />

The following is an example of a server-side method with an &html block, in which a runtime<br />

expression invokes the ObjectScript function $ZCONVERT ($ZCVT) to help it to write out the elements<br />

of a bulleted list:<br />

Method %DrawHTML()<br />

{<br />

&html<br />

Write $ZCVT(..text,"O","HTML")<br />

}<br />

#; bullets<br />

Set tCount = ..bullets.Count()<br />

If (tCount > 0) {<br />

&html<br />

For n = 1:1:tCount {<br />

Set tBullet = ..bullets.GetAt(n)<br />

&html<br />

}<br />

&html<br />

}<br />

}<br />

&html<br />

The following is an example of a <strong>Zen</strong>Method with a &js block, in which a runtime expression<br />

passes the server-side identifier pIndex to JavaScript code that needs to execute on the client. In a later<br />

&js block, runtime expressions invoke the ObjectScript function $RANDOM ($R) to produce<br />

drawing coordinates, and provide CSS style statements to configure a graphical object:<br />

ClassMethod GetSVGContents(pIndex As %Integer) [ <strong>Zen</strong>Method ]<br />

{<br />

#; get the svg component<br />

&js<br />

}<br />

#; lines<br />

For i=1:1:30 {<br />

&js<<br />

var line = svg.document.createElementNS(SVGNS,'circle');<br />

//line.setAttribute('x1',200);<br />

//line.setAttribute('y1',100);<br />

line.setAttribute('r',5);<br />

line.setAttribute('cx',#(10+$Random(380))#);<br />

line.setAttribute('cy',#(10+$Random(180))#);<br />

line.setAttribute('style',<br />

'#("fill: yellow; stroke: black; stroke-width: 2;")#');<br />

svg.svgGroup.appendChild(line);<br />

><br />

}<br />

Quit<br />

The following is an example of a <strong>Zen</strong>Method that uses a &js block, in which runtime expressions<br />

call server-side methods of the server-side %page object to compose a JavaScript alert message:<br />

370 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Page Classes<br />

Method serverInstanceMethod() [ <strong>Zen</strong>Method ]<br />

{<br />

#; The server returns the following JavaScript statements to<br />

#; client for execution.<br />

&js<<br />

alert('Server instance method');<br />

alert('page: #(%page)#');<br />

alert('child 1: #(%page.children.GetAt(1))#');<br />

alert('title by id: #(%page.%GetComponentById("title"))#');<br />

alert('menu by id: #(%page.%GetComponentById("menu"))#');<br />

><br />

}<br />

Note:<br />

The samples in this topic demonstrate how runtime expressions can be used in a server-side<br />

method. In a client-side JavaScript method, you can achieve similar results without using<br />

runtime expressions.<br />

18.3.4 <strong>Zen</strong> Page Properties<br />

Any property defined within a page class whose name does not start with % becomes a property of the<br />

client-side page object. These client-side properties are initialized to the values they held on the server<br />

side, immediately before the page’s %DrawHTML method was invoked.<br />

You cannot set the value of any properties that you add to your page class by using the element<br />

within the XData Contents block. Only properties defined by the parent class %ZEN.Component.page<br />

are available in XData Contents.<br />

You can provide initial values for page class properties in one of the following ways:<br />

• Define an InitialExpression for the property, as in:<br />

Property dayList As %ZEN.Datatype.caption<br />

[ InitialExpression = "Sun,Mon,Tue,Wed,Thu,Fri,Sat" ];<br />

• Set the property in the %OnCreatePage or %OnAfterCreatePage callback methods.<br />

You can also set a page property’s value at runtime within any other method; these are just ways to<br />

initialize them.<br />

18.3.5 <strong>Zen</strong> Utility Methods<br />

The %ZEN.Utils class includes a number of utility methods for performing various common functions.<br />

Most of these classes are for internal use by the <strong>Zen</strong> library.<br />

ZENTest.LogPage in the SAMPLES namespace is an example of a page class that uses some of these<br />

utility methods to respond to the user’s selection of whether or not to enable logging for the application.<br />

The page class provides:<br />

• A definition for the event log display, plus the following :<br />

<strong>Using</strong> <strong>Zen</strong> 371


<strong>Zen</strong> Application Programming<br />

<br />

• This client-side method:<br />

Method enabledChange(cb) [ Language = javascript ]<br />

{<br />

this.EnableLog(cb.getValue()==1 true : false);<br />

}<br />

this.refreshLog();<br />

• And this <strong>Zen</strong> method:<br />

ClassMethod EnableLog(flag As %Boolean = "") As %Boolean [ <strong>Zen</strong>Method ]<br />

{<br />

If (flag = "") {<br />

Set flag = ##class(%ZEN.Utils).%LoggingEnabled()<br />

}<br />

If (flag) {<br />

Do ##class(%ZEN.Utils).%StartLog()<br />

}<br />

Else {<br />

Do ##class(%ZEN.Utils).%StopLog()<br />

}<br />

Quit 1<br />

}<br />

The result is as follows:<br />

Sample Log of <strong>Zen</strong> Events<br />

To read more about %ZEN.Utils, start the Caché online documentation system and choose Class Reference<br />

<strong>Documentation</strong> for the %SYS namespace.<br />

18.3.6 Client-Side Functions and Variables<br />

All page classes have the following JavaScript utility functions and variables available to them:<br />

372 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Page Classes<br />

Client-Side Functions and Variables<br />

Function or Variable<br />

zenLaunchPopupWindow<br />

zenLink<br />

zenSynchronousMode<br />

Description<br />

A function that launches the referenced HTML content as<br />

a popup window. See the chapter Popup Windows and<br />

Dialogs, topic Popup Windows.<br />

A function that escapes any special characters found in a<br />

string intended to be used as a URI. See the chapter Popup<br />

Windows and Dialogs, topic Popup Windows.<br />

A flag with the value true (all methods will be executed<br />

synchronously regardless of whether or not they have return<br />

values) or false (methods will be synchronous if they have<br />

a return value, asynchronous otherwise). See Synchronous<br />

and Asynchronous Methods, later in this chapter.<br />

18.3.7 <strong>Zen</strong> Page URI Parameters<br />

Sometimes it is useful to pass values to a page via URI parameters.<br />

There is a datatype parameter, ZENURL, that can be applied to properties of page classes. The presence<br />

of this parameter causes the page to generate code that will initialize the value of the datatype to the<br />

value of a URI parameter.<br />

For example, in a page class you can define a property:<br />

Property employeeID As %ZEN.Datatype.string(ZENURL="ID");<br />

When this page is requested, the value of the URI parameter, ID, will be assigned to the employeeID<br />

property. For example, this URI:<br />

MyApp.MyPage.clsID=48<br />

Will cause the following code to run:<br />

Set %page.employeeID = $GET(%request.Data("ID",1))<br />

If the URI parameter assigned to a property does not pass the property’s validation test for any reason,<br />

such as a value greater than the property’s MAXVAL, the page is not displayed and an error message<br />

is displayed instead.<br />

<strong>Using</strong> <strong>Zen</strong> 373


<strong>Zen</strong> Application Programming<br />

18.3.8 <strong>Zen</strong> Page Event Handling<br />

Many components define event handlers such as onclick, onchange, etc. See the description of any<br />

<strong>Zen</strong> control component, such as , , or . Also see the description of zenEvent<br />

in the topic <strong>Zen</strong> Special Variables, above.<br />

While a page is being displayed, <strong>Zen</strong> traps all events until the page finished building. This is to prevent<br />

the user from clicking on an element before the browser has finished building the zenPage object on<br />

the client side.<br />

18.4 <strong>Zen</strong> Properties on Client and Server<br />

On the server side, you can get and set values of class properties directly, using normal dot syntax.<br />

For example:<br />

Method serverInstanceMethodCreate() [ <strong>Zen</strong>Method ]<br />

{<br />

#; create<br />

Set group = %page.%GetComponentById("group")<br />

If '$IsObject(group) {<br />

&js<br />

Quit<br />

}<br />

Set count = group.children.Count()<br />

}<br />

Set cal = ##class(%ZEN.Component.calendar).%New()<br />

Set cal.id = "NewCal"_count<br />

Do group.%AddChild(cal)<br />

Set btn = ##class(%ZEN.Component.button).%New()<br />

Set btn.id = "NewBtn"_count<br />

Set btn.caption = "New Button"<br />

Do group.%AddChild(btn)<br />

Set btn = ##class(%ZEN.Component.text).%New()<br />

Set btn.label = "Hey"<br />

Do group.%AddChild(btn)<br />

On the client side, you cannot access any property values directly. You must use the get and set<br />

methods provided in the component classes. For single-valued properties, use the getProperty and<br />

setProperty methods. For example:<br />

var index = table.getProperty('selectedIndex');<br />

Or:<br />

var svg = zenPage.getComponentById('svgFrame');<br />

svg.setProperty('layout','');<br />

svg.setProperty('editMode','drag');<br />

374 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Methods<br />

Important:<br />

Do not confuse getProperty and setProperty with the getValue and setValue<br />

methods, which get and set the value of a control component, and do not apply to any<br />

other component property.<br />

18.5 <strong>Zen</strong> Methods<br />

The following table outlines the possibilities for different types of method in a <strong>Zen</strong> page class.<br />

Page Class Method Conventions<br />

Callable<br />

From<br />

Runs On<br />

Class<br />

Scope<br />

Timing<br />

Code<br />

Language<br />

Keyword<br />

Naming<br />

Convention<br />

Client<br />

Client<br />

Instance<br />

—<br />

JavaScript<br />

Language<br />

=<br />

JavaScript<br />

myMethod<br />

Client<br />

Server<br />

(Can send<br />

back code<br />

that runs on<br />

the client)<br />

Instance<br />

Class<br />

Async<br />

Sync<br />

Async<br />

Sync<br />

ObjectScript<br />

or Basic<br />

<strong>Zen</strong>Method<br />

MyMethod<br />

Server<br />

Server<br />

Instance<br />

Class<br />

—<br />

ObjectScript<br />

or Basic<br />

—<br />

%MyMethod<br />

Any method defined within a page class whose name does not start with % becomes a method of the<br />

client-side page object. Any method whose name starts with % is server-only.<br />

Any instance method defined as having [Language = javascript] automatically becomes a<br />

client-side instance method of the client page object. When called, it executes within the browser.<br />

Any method defined with its [<strong>Zen</strong>Method] keyword set automatically becomes a client-side instance<br />

method of the client page object. When the client-side method is called, the server-side version of the<br />

method is executed. Any context needed to run the server method is automatically provided. An instance<br />

method runs as an instance method on the server; the serialized state of its client object is shipped to<br />

the server and instantiated. A class method runs as a class method on the server (but is called as an<br />

instance method on the client).<br />

<strong>Using</strong> <strong>Zen</strong> 375


<strong>Zen</strong> Application Programming<br />

18.5.1 Synchronous and Asynchronous Methods<br />

Server-side methods can be called synchronously or asynchronously. This happens very smoothly and<br />

automatically as follows: If a server-side method has a return type, it is called synchronously, and its<br />

return value is returned to the client. If the method has no return type, it is called asynchronously; the<br />

client does not wait for the return value.<br />

The CSP hyper-event logic handles all the details of this, so (unlike AJAX) you do not need to provide<br />

any additional application logic to enable asynchronous calls. In this way, <strong>Zen</strong> takes the next step past<br />

most AJAX frameworks.<br />

The main advantages of asynchronous methods are:<br />

• The browser can keep working while the server request is processed<br />

• You can call a server method, modify the client (say by displaying a message), and the server<br />

logic can update this message when it completes<br />

Some of the <strong>Zen</strong> components take advantage of asynchronous methods. For example, the <br />

control uses an asynchronous method to execute a server-side query. This allows the <br />

to display a loading... message while the query is running. This message is replaced when the<br />

response from the server arrives, so the user does not see the message if the query is quick.<br />

<strong>Zen</strong> offers a client-side flag zenSynchronousMode that you can set to true to force all methods to<br />

be executed synchronously, regardless of their return values. When false, methods are synchronous<br />

if they have a return value, asynchronous otherwise. When you want to set this flag:<br />

1. First, get and store the current value of zenSynchronousMode.<br />

2. Then, set the flag as you wish.<br />

3. When your processing is done, restore the previous value of zenSynchronousMode.<br />

In addition to this convention, the client-side refreshContents method (available for every component)<br />

offers a single optional argument whose value can be true or false. This flag specifies whether the<br />

client should refresh the component synchronously (true) or asynchronously (false). If this argument<br />

is omitted, the default is false.<br />

18.5.2 Server-Side Callback Methods<br />

Callback methods are user-written methods within a Caché class that are triggered, not by a method<br />

call, but by specific system events. To distinguish callback methods, Caché developers give them<br />

names of the following form:<br />

%OnEvent<br />

376 <strong>Using</strong> <strong>Zen</strong>


where the keyword Event identifies the Caché system event that triggers the callback. If an event<br />

supports a callback method, the method controlling the event automatically executes the callback<br />

method, if it exists within the class.<br />

You must never execute callback methods by calling them explicitly. Instead, provide an implementation<br />

of the method within your class so that Caché can invoke the method automatically when the time is<br />

right. If you want your class to do nothing in response to an event, omit any implementation of the<br />

corresponding callback method.<br />

When an HTML page derived from %ZEN.Component.page is drawn, it invokes a number of callback<br />

methods that are executed on the server before the page content is sent to the browser. The following<br />

table lists these methods. A page class can override these methods to control the behavior of the page.<br />

Page Class Server-side Callback Methods<br />

<strong>Zen</strong> Methods<br />

Callback Method<br />

%OnBeforeCreatePage<br />

%OnCreatePage<br />

%OnAfterCreatePage<br />

%OnDrawHTMLHead<br />

%OnDrawHTMLBody<br />

Description<br />

This class method is called just before the server-side page<br />

object is created.<br />

This instance method is called just after the server-side page<br />

object is created but before any of its child components are<br />

created.<br />

This instance method is called after the server-side page object<br />

and all of its pre-defined child components are created. A<br />

subclass can override this method to add, remove, or modify<br />

items within the page object model, or to provide values for<br />

controls.<br />

This instance method is called when the HTML for the page is<br />

being rendered just before the end of the HTML HEAD section<br />

of the page. This provides a way to inject addition content into<br />

the HEAD section of a page should this ever be necessary.<br />

This instance method is called when the HTML for the page is<br />

being rendered close to the start of the HTML BODY section<br />

of the page (before any child components are rendered). This<br />

provides a way to inject additional content into the BODY<br />

section of a page should this ever be necessary.<br />

For details about each method see the class documentation for %ZEN.Component.abstractPage. That<br />

is, start the Caché online documentation system, choose Class Reference <strong>Documentation</strong> for the %SYS<br />

namespace, and navigate to %ZEN.Component.abstractPage.<br />

<strong>Using</strong> <strong>Zen</strong> 377


<strong>Zen</strong> Application Programming<br />

18.5.3 Server-Only Methods<br />

The %ZEN.Component.page class contains a number of server-side methods that can be useful when<br />

working with the page object tree on the server or for processing form submits. The following table<br />

lists these methods.<br />

Page Class Server Methods<br />

Method<br />

%GetComponent<br />

%GetComponentById<br />

%GetComponentByName<br />

%GetValueById<br />

%GetValueByName<br />

%SetErrorById<br />

%SetErrorByName<br />

%SetValueById<br />

%SetValueByName<br />

%SetValuesByName<br />

Description<br />

Find a component object given its system-assigned index<br />

number.<br />

Find a component object given its user-assigned id value.<br />

Find a control object given its user-assigned control name.<br />

Get the value of a control object given its user-assigned<br />

control id value.<br />

Get the value of a control object given its user-assigned<br />

control name.<br />

Set the value of a component error message given its<br />

user-assigned id value.<br />

Set the value of a component error message given its<br />

user-assigned control name.<br />

Set the value of a control object given its user-assigned<br />

control id value.<br />

Set the value of a control object given its user-assigned<br />

control name.<br />

Set the values of a set of control objects given an array of<br />

values subscripted by user-assigned control name.<br />

For details about each method see the class documentation for %ZEN.Component.abstractPage.<br />

18.5.4 Type Conversion for Server-Side Methods<br />

The mechanism for handling type conversions when invoking a server-side method works as follows:<br />

• When calling a server-side method, any %ZEN.Datatype.boolean arguments are converted from<br />

client-side true/false to server-side 1/0.<br />

• If a server method has a %ZEN.Datatype.boolean return type, its return value are converted to a<br />

client-side true/false value.<br />

378 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Methods<br />

• If a server method has a numeric return type, its return value are converted to a client-side numeric<br />

value (unless it the method returns "").<br />

• Methods that take object-valued arguments behave well if the argument is missing or null.<br />

18.5.5 Background Tasks on the Server<br />

There is a mechanism for starting a background job from a <strong>Zen</strong> page and tracking its progress within<br />

the page. This can be useful for cases where a page needs to initiate a long-running task and wants to<br />

provide some degree of feedback to the client while waiting for that task to complete.<br />

A <strong>Zen</strong> page class has a backgroundTimerInterval property. This is the interval, in milliseconds, at which<br />

timer events are fired to check on the status of background tasks started by this page. The default is<br />

1000.<br />

Two methods support background tasks; both are available in any class that inherits from<br />

%ZEN.Component.page:<br />

• %RunBackgroundMethod starts a background job to run a class method of this <strong>Zen</strong> page.<br />

%RunBackgroundMethod returns a %Status value and may have one or more arguments:<br />

- The first argument, a %String, is the name of the class method to run.<br />

- Depending on the method signature, a variable number of arguments may follow; these are<br />

the arguments of the method named in the first argument.<br />

<strong>Zen</strong> monitors only one background task at a time. If %RunBackgroundMethod is called while<br />

a previous background task is running, the new method becomes the current monitored task. The<br />

previous task runs to completion, but the client is not notified about it.<br />

• %SetBackgroundMethodStatus can be called from within a method that is running in the<br />

background, to update its own status information. %SetBackgroundMethodStatus has no return<br />

value and takes two arguments:<br />

- A %String specifies the status message that will be seen by the client page. The string may<br />

be empty.<br />

- An optional %Float value indicates how much of the background task is complete (as a percentage<br />

between 0 and 100). A client page can use this information to display progress to the<br />

user.<br />

18.5.6 Client-Side Page Callback Methods<br />

The client-side page object zenPage inherits a number of callback methods. These are JavaScript<br />

methods which, if defined, are called in response to specific events. The following table lists these<br />

methods.<br />

<strong>Using</strong> <strong>Zen</strong> 379


<strong>Zen</strong> Application Programming<br />

Page Class Client-side Callback Methods<br />

Callback Method<br />

onloadHandler<br />

onpopupAction<br />

onresizeHandler<br />

onunloadHandler<br />

Description<br />

This client-side page method, if defined, is called when the client<br />

page is finished loading (i.e. it is called by the page’s HTML onload<br />

event).<br />

This client-side page method, if defined, is called when a popup<br />

window, launched by this page, is completed.<br />

This client-side page method, if defined, is called when the client<br />

page is resized (it is called by the page’s HTML onresize event).<br />

This client-side page method, if defined, is called when the client<br />

page is about to unload (it is called by the page’s HTML onunload<br />

event).<br />

18.5.7 Client-Side Page Methods<br />

The client-side page object zenPage inherits a number of JavaScript methods that can be useful in<br />

client-side programming. The following table lists these methods.<br />

Page Class Client-side Methods<br />

Method<br />

cancelPopup<br />

createComponent<br />

createComponentNS<br />

endModal<br />

getComponent<br />

getComponentById<br />

startModal<br />

Description<br />

(Popup windows only). Close the current popup window with no<br />

further action.<br />

Create a new component on the page (by component name).<br />

Create a new component on the page (by component name and<br />

namespace).<br />

Hide the current modalGroup, if there is one.<br />

Find a component on the page given its system-assigned index<br />

number.<br />

Find a component on the page given its user-assigned id value.<br />

Make a modalGroup visible. Alternately, use the show method<br />

of the modalGroup.<br />

380 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Page Contents<br />

18.5.8 Client-Side Component Methods<br />

Every component on the page (including the page itself) inherits a number of useful JavaScript methods.<br />

The following table lists these methods. Specific components also have specialized methods not listed<br />

in the table.<br />

Page Class Client-side Component Methods<br />

Method<br />

findElement<br />

getEnclosingDiv<br />

getHidden<br />

getProperty<br />

getSettings<br />

getValue<br />

invokeSuper<br />

isOfType<br />

refreshContents<br />

setHidden<br />

setProperty<br />

setValue<br />

Description<br />

Find a named HTML element associated with a specific component.<br />

Get the HTML div element used to enclose a specific component.<br />

Return whether a component is hidden (or displayed).<br />

Return a named property of a component.<br />

Get the set of named properties that can be observed and modified<br />

using getProperty and setProperty.<br />

(Subclasses of control only). Get the value of a control. This is<br />

equivalent to calling getProperty('value').<br />

Invoke the super class implementation of the current component<br />

method.<br />

Tests if a component is a subclass of (is a type of) another component.<br />

Make a request to the server to regenerate the HTML that defines a<br />

component. For tablePane components, use executeQuery instead.<br />

Sets whether a component is hidden (or displayed).<br />

Sets the value of a named property for a component.<br />

(Subclasses of control only). Set the value of a control.<br />

18.6 <strong>Zen</strong> Page Contents<br />

This topic explains how to specify the component object model for a <strong>Zen</strong> page using XML, programmatically,<br />

or with a combination of both.<br />

The visible contents of the page are defined by a set of <strong>Zen</strong> components that belong to the page. This<br />

set of components is typically defined within an XML block named XData Contents. It is also possible<br />

to define or modify this set of components by overriding the %OnAfterCreatePage callback method.<br />

<strong>Using</strong> <strong>Zen</strong> 381


<strong>Zen</strong> Application Programming<br />

18.6.1 Defining Page Contents <strong>Using</strong> XML<br />

A <strong>Zen</strong> page class can provide an XData Contents block (an XML document embedded within the<br />

class definition) that defines the set of components that will be used for the page. It is possible to define<br />

the contents of a page programmatically, but in most cases an XML block is more convenient.<br />

The following XData Contents block defines a simple page object containing a single button<br />

component:<br />

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]<br />

{<br />

<br />

<br />

<br />

}<br />

The XData Contents block is not processed at runtime. Instead, at compile time the class compiler<br />

uses the XData Contents information to generate a method called %CreatePage. You can view<br />

(but not modify) this method if you like by compiling a page class and then using the View Other<br />

command in Studio to see the code generated for the page class. The %CreatePage method is called<br />

at runtime to create the contents of the page component model.<br />

<strong>Zen</strong> Layout and the chapters that follow it describe XData Contents in detail.<br />

18.6.2 XML Namespaces<br />

<strong>InterSystems</strong> recommends that you include an XML namespace declaration within an XData Contents<br />

definition. You do this by providing the xmlns attribute with the element. For example:<br />

<br />

As you add custom components, chances increase that there will be conflicts between components in<br />

different namespaces. This is also true for other <strong>Zen</strong> elements such as and . Adding<br />

the xmlns attribute to the prevents this.<br />

18.6.3 Defining Page Contents Programmatically<br />

If you need to programmatically modify the contents of a page before displaying it, add code to the<br />

%OnAfterCreatePage callback method to do so. You can find a component on the page using the<br />

%GetComponentById method, then set component properties directly. Then you must add the new<br />

component to a group or page using %AddChild. For example:<br />

382 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Page Contents<br />

Method %OnAfterCreatePage() As %Status<br />

{<br />

Set tGroup = ##class(%ZEN.Component.group).%New()<br />

Do %page.%AddChild(tGroup)<br />

Set tBtn = ##class(%ZEN.Component.button).%New()<br />

Set tBtn.caption = "Button 1"<br />

Do tGroup.%AddChild(tBtn)<br />

Set tBtn = ##class(%ZEN.Component.button).%New()<br />

Set tBtn.caption = "Button 2"<br />

Do tGroup.%AddChild(tBtn)<br />

}<br />

Quit $$$OK<br />

Any text you add for captions or other labels is not magically localized as it is when you add a caption<br />

attribute using XML. If you want localized captions, your %OnAfterCreatePage methods must call<br />

the $$$Text localization macros. This is not shown in the example above.<br />

If the component is not visible (such as ) you may add it to a page using %AddComponent<br />

instead of %AddChild. For components that are visible, the methods %AddChildBefore and<br />

%AddChildAfter are also available. These methods have a second parameter that identifies the<br />

existing, sibling component.<br />

If you need to add components to a page programmatically, based on user interactions, you can do this<br />

as well. The SAMPLES namespace class ZENTest.DynamicComponentsTest provides useful examples<br />

of doing this from the client or server sides in response to user input. Remember that you need to both<br />

create the component and add it as a child of the page before the user can see it. A separate set of<br />

methods exists for doing this on the server and on the client (see the lists in previous topics). As another<br />

example of dynamically adding components to a page, see the Sample Development Project, below.<br />

One of the best ways to get a sense of how pages are put together programmatically is to look at the<br />

generated code for the %CreatePage method in any <strong>Zen</strong> page class that uses XData Contents to define<br />

page contents. To do this:<br />

1. Open the page class in Studio.<br />

2.<br />

Choose View > View Other or Ctrl-Shift-V or the<br />

icon.<br />

3. Select the file marked “1” and click Open.<br />

4. Search for this string: %CreatePage<br />

5. Scroll through the method to see how components are added to the page.<br />

18.6.4 <strong>Zen</strong> Layout Handler<br />

The actual work of laying out a group component’s children is handled by the %ZEN.LayoutManager<br />

class. It is possible to implement layout strategies in addition to those normally provided. If you wish<br />

to serve the page using your own, custom layout handler code, you can.<br />

<strong>Using</strong> <strong>Zen</strong> 383


<strong>Zen</strong> Application Programming<br />

<strong>Zen</strong> provides a simple, built-in layout strategy with the intention of making rapid application development<br />

easier. Components start at top left of the page and work their way to the right and bottom. You<br />

can achieve a lot, very quickly, by manipulating nests of vertical and horizontal groups.<br />

There may be cases when your layout needs finer control. If so, ultimately it might suit your project<br />

best to develop your own layout handler for use with <strong>Zen</strong>. For these cases, <strong>Zen</strong> provides an<br />

onlayoutHandler callback method. This client-side method, if defined, is called when a page is first<br />

displayed and whenever the size of the page is changed thereafter. This provides a way to define code<br />

that will adjust the size and position of components whenever the size of the containing page is changed.<br />

For example:<br />

Method onlayoutHandler(load) [ Language = javascript ]<br />

{<br />

// adjust size of lookout menu<br />

var menu = zenPage.getComponentById('lookout');<br />

zenASSERT(menu,'Unable to find menu',arguments);<br />

}<br />

// find div for titleBox & mainMenu<br />

var title = zenPage.getComponentById('titleBox');<br />

var divTitle = title.getEnclosingDiv();<br />

// find height of window<br />

var winHeight = zenGetWindowHeight();<br />

// adjust size of menu<br />

var sz =<br />

winHeight - (parseInt(divTitle.offsetHeight)) - 20;<br />

menu.setSize(null,sz);<br />

18.7 Sample Development Project<br />

The chapter <strong>Zen</strong> Layout explains how to use template pages and panes to organize layout and style<br />

for a <strong>Zen</strong> application. This topic traces an example that uses composites and dynamic page generation<br />

to organize behavior for a <strong>Zen</strong> application. This example uses <strong>Zen</strong> to add new order entry module<br />

pages to an existing Weblink application. Constraints are as follows:<br />

• You need to be able to call the new pages from within your existing application.<br />

• You do not have the luxury of rewriting the whole application, so you want to evolve into <strong>Zen</strong><br />

one module at a time.<br />

• Your order entry page needs to have flexible content. That is, you need to be able to easily update<br />

portions of the page depending on the context.<br />

• Your order entry page is so big and complex, you want to only build what you need when the<br />

page is first loaded and then fill in some empty segments on the fly.<br />

• Ideally, you want to break up the page into segments that can be written simultaneously by different<br />

developers.<br />

384 <strong>Using</strong> <strong>Zen</strong>


Sample Development Project<br />

The following example addresses these constraints. It purposely does not address layout or style but<br />

focuses on behavior.<br />

• The following class provides the main page. It defines a set of named groups. Each group is populated<br />

with components from the server in response to user events. The main page also defines<br />

an API (set of methods) that the various components can call to work with the page. For example,<br />

there is a method that loads a new component into one of the groups on the page. Note the<br />

parameter USERPACKAGES, the groups g1 and g2, and the method loadForm, which adds a<br />

specific type of form to the page based on the parameters provided to it.<br />

• The contents of each group is defined using a composite component. A composite is a custom<br />

component that you build by grouping one or more built-in <strong>Zen</strong> components in a specific way.<br />

For full details, see the chapter Custom Components, topic Building Composite Components.<br />

Composites can be developed individually by different developers; this satisfies the project constraints.<br />

In the sample code, there are four such composites: searchForm is the starting form that<br />

drives the loading of other forms. formOne, formTwo, and formThree are sample forms.<br />

<strong>Using</strong> <strong>Zen</strong> 385


<strong>Zen</strong> Application Programming<br />

Class TestMe.MainPage Extends %ZEN.Component.page<br />

{<br />

/// Comma-separated list of User class packages whose HTML class<br />

/// and style definitions are in pre-generated include files.<br />

Parameter USERPACKAGES = "TestMe.Components";<br />

/// Class name of application this page belongs to.<br />

Parameter APPLICATION;<br />

/// Displayed name of this page.<br />

Parameter PAGENAME;<br />

/// Domain used for localization.<br />

Parameter DOMAIN;<br />

/// This Style block contains page-specific CSS style definitions.<br />

XData Style<br />

{<br />

<br />

/* style for title bar */<br />

#title {<br />

background: #C5D6D6;<br />

color: black;<br />

font-family: Verdana;<br />

font-size: 1.5em;<br />

font-weight: bold;<br />

padding: 5px;<br />

border-bottom: 1px solid black;<br />

text-align: center;<br />

}<br />

}<br />

/* container style for group g1 */<br />

#g1 {<br />

border: 1px solid black;<br />

background: #DDEEFF;<br />

}<br />

/* container style for group g2 */<br />

#g2 {<br />

border: 1px solid black;<br />

background: #FFEEDD;<br />

}<br />

<br />

/// This XML block defines the contents of this page.<br />

XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />

{<br />

<br />

TestMe Test Page<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

/// Create a form (via a composite element) and place it into the group with<br />

/// the id groupId. formClass is the name of the composite element<br />

386 <strong>Using</strong> <strong>Zen</strong>


Sample Development Project<br />

/// containing the form. formId is the id applied to the form.<br />

Method loadForm(formClass, formId, groupId) [ Language = javascript ]<br />

{<br />

try {<br />

// if there is already a form, get rid of it<br />

var comp = zenPage.getComponentById(formId);<br />

if (comp) {<br />

zenPage.deleteComponent(comp);<br />

}<br />

}<br />

}<br />

var group = zenPage.getComponentById(groupId);<br />

var form = zenPage.createComponentNS('TestMe',formClass);<br />

form.setProperty('id',formId);<br />

group.addChild(form);<br />

group.refreshContents(true);<br />

}<br />

catch(ex) {<br />

zenExceptionHandler(ex,arguments);<br />

}<br />

Some important things to notice about the TestMe.MainPage class:<br />

• The parameter USERPACKAGES is set as follows:<br />

Parameter USERPACKAGES = "TestMe.Components";<br />

This tells the page to use the generated include files for the components in this package. This is<br />

important as we are creating things on-the-fly and we want to ensure that the relevant JS object<br />

are available.<br />

• The XData Contents block for the page provides a reference to the XML namespace for the new<br />

composite components:<br />

xmlns:testme="TestMe"<br />

• XData Contents places the searchForm component on the page as follows:<br />

<br />

When the user presses one of the buttons on the searchForm, it invokes the loadForm method on<br />

the Main page. This deletes the current form (by id) and loads a new form (it does not actually<br />

have to be a form, that is just what we have used as an example).<br />

Now take a look at the components for the example. As suggested in Building Composite Components,<br />

all of these composite component classes are placed together in their own package, TestMe.Components.<br />

The reason for this is that <strong>Zen</strong> will automatically generate JS and CSS header files for components in<br />

a given package. By placing these components in a package you can exploit this feature by setting the<br />

parameter USERPACKAGES to the package name, on the main page, as shown above:<br />

Parameter USERPACKAGES = "TestMe.Components";<br />

The composites also use their own XML namespace to avoid conflict with other components.<br />

The composite component classes are as follows:<br />

<strong>Using</strong> <strong>Zen</strong> 387


<strong>Zen</strong> Application Programming<br />

• searchForm — the starting form that drives the loading of other forms:<br />

Class TestMe.Components.searchForm Extends %ZEN.Component.composite<br />

{<br />

/// This is the XML namespace for this component.<br />

Parameter NAMESPACE = "TestMe";<br />

/// This Style block contains component-specific CSS style definitions.<br />

XData Style<br />

{<br />

<br />

}<br />

<br />

}<br />

/// Contents of this composite component.<br />

XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />

{<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

/// User click on form 1 button.<br />

Method btnForm1() [ Language = javascript ]<br />

{<br />

// Notify the page that the search button was pressed<br />

// and that a new form should be loaded.<br />

zenPage.loadForm('formOne','form1','g1');<br />

}<br />

/// User click on form 2 button.<br />

Method btnForm2() [ Language = javascript ]<br />

{<br />

// replace contents of 'g1' with formTwo<br />

zenPage.loadForm('formTwo','form1','g1');<br />

}<br />

/// User click on form 3 button.<br />

Method btnForm3() [ Language = javascript ]<br />

{<br />

// replace contents of 'g2' with formTwo<br />

zenPage.loadForm('formTwo','form2','g2');<br />

}<br />

/// User click on form 4 button.<br />

Method btnForm4() [ Language = javascript ]<br />

{<br />

// replace contents of 'g2' with formThree<br />

zenPage.loadForm('formThree','form2','g2');<br />

}<br />

Every component that is part of a composite can refer to its containing composite group via its<br />

composite property. You can see this in the syntax used to invoke client-side methods defined in<br />

the composite class, when the user clicks a button on this form:<br />

onclick="zenPage.getComponent(#(..index)#).btnForm1();"<br />

• formOne — a sample form:<br />

388 <strong>Using</strong> <strong>Zen</strong>


Class TestMe.Components.formOne Extends %ZEN.Component.composite<br />

{<br />

/// This is the XML namespace for this component.<br />

Parameter NAMESPACE = "TestMe";<br />

Sample Development Project<br />

/// This Style block contains component-specific CSS style definitions.<br />

XData Style<br />

{<br />

<br />

}<br />

<br />

/// Contents of this composite component.<br />

XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />

{<br />

<br />

}<br />

}<br />

<br />

<br />

<br />

• formTwo — another sample form:<br />

Class TestMe.Components.formTwo Extends %ZEN.Component.composite<br />

{<br />

/// This is the XML namespace for this component.<br />

Parameter NAMESPACE = "TestMe";<br />

/// This Style block contains component-specific CSS style definitions.<br />

XData Style<br />

{<br />

<br />

}<br />

<br />

/// Contents of this composite component.<br />

XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />

{<br />

<br />

}<br />

}<br />

<br />

<br />

<br />

<br />

<br />

<br />

• formThree — yet another sample form:<br />

<strong>Using</strong> <strong>Zen</strong> 389


<strong>Zen</strong> Application Programming<br />

Class TestMe.Components.formThree Extends %ZEN.Component.composite<br />

{<br />

/// This is the XML namespace for this component.<br />

Parameter NAMESPACE = "TestMe";<br />

/// This Style block contains component-specific CSS style definitions.<br />

XData Style<br />

{<br />

<br />

}<br />

<br />

/// Contents of this composite component.<br />

XData Contents [ XMLNamespace = "http://www.intersystems.com/zen" ]<br />

{<br />

<br />

<br />

<br />

<br />

}<br />

/// colorChange<br />

Method colorChange(color) [ Language = javascript ]<br />

{<br />

alert('You have selected: ' + color);<br />

}<br />

}<br />

390 <strong>Using</strong> <strong>Zen</strong>


19<br />

<strong>Zen</strong> Security<br />

You can provide application-level security for <strong>Zen</strong> using CSP application settings. See the Caché<br />

Security Administration Guide, chapter Assets and Resources, topic Application Resources and Their<br />

Privileges.<br />

There are additional techniques for controlling access to pages and components within a <strong>Zen</strong> application.<br />

19.1 Controlling Access to Applications<br />

By default, when a user starts your <strong>Zen</strong> application it prompts the user to log in by displaying the<br />

standard Caché username and password dialog box. If you wish your application to present a custom<br />

login form, you must create and configure this form as follows:<br />

1. Create a new <strong>Zen</strong> page class.<br />

2. Within XData Contents, provide a whose nextPage value is the first <strong>Zen</strong> page that you<br />

want the user to see, upon successfully logging in:<br />

<br />

<br />

<br />

<br />

3. Make sure that, at minimum, this contains the following controls:<br />

• for the username<br />

• for the password<br />

Ensure that you provide a name attribute for each of these controls and that the corresponding<br />

name values are exactly as shown above: "CacheUserName" and "CachePassword". You<br />

<strong>Using</strong> <strong>Zen</strong> 391


<strong>Zen</strong> Security<br />

may provide other attributes for the controls as desired; a label is useful for each control so that<br />

the user knows what to enter.<br />

4. Provide a button. Your minimal user login form now looks like this:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

5. Define other characteristics of the form as desired.<br />

6. Start the Caché System Management Portal.<br />

7. Navigate to the [Home] > [Security Management] > [CSP Applications] page.<br />

8. Find your <strong>Zen</strong> application in the list and click its Edit button. The [Home] > [Security Management]<br />

> [CSP Applications] > [Edit CSP Application] page displays.<br />

9. In the Login Page field, enter the pathname of your new <strong>Zen</strong> page class. This pathname is relative<br />

to the Caché installation directory, for example:<br />

/csp/myApp/myLoginPage.cls<br />

10. Click Save.<br />

19.2 Controlling Access to Pages<br />

Each <strong>Zen</strong> page has a class parameter called RESOURCE that, if defined, provides the name of a system<br />

Resource for which the current user must hold USE privileges in order to view this page or to invoke<br />

any of its server-side methods from the client.<br />

19.3 Controlling Access to Components<br />

Each <strong>Zen</strong> component (subclass of %ZEN.Component.component) has a server-only property called<br />

%resource that determines whether or not this component should be added to the set of page components.<br />

The component projects this property to XML as an attribute called resource. You can use this resource<br />

when adding a component to XData Contents. For example:<br />

<br />

392 <strong>Using</strong> <strong>Zen</strong>


Controlling Access to Components<br />

If a resource value is specified, the current user must hold USE privileges on this resource or the<br />

component will not be added to the set of page components when the user attempts to display the page.<br />

This property is not available from the client.<br />

<strong>Using</strong> <strong>Zen</strong> 393


20<br />

<strong>Zen</strong> Localization<br />

When you localize the text for an application, you create an inventory of text strings in one language,<br />

then establish a convention for substituting translated versions of these messages when the application<br />

locale is different. Most of the information you need to localize <strong>Zen</strong> pages can be found in the book<br />

<strong>Using</strong> Caché Server Pages, chapter Localizing Text in a CSP Application. Everything described in<br />

that chapter for development of CSP pages also applies to <strong>Zen</strong> pages.<br />

There are a few additional details that apply only to <strong>Zen</strong>. This chapter:<br />

• Summarizes the CSP information<br />

• Describes <strong>Zen</strong> extensions to CSP techniques<br />

20.1 CSP Localization<br />

Important:<br />

This topic briefly outlines material from the Localizing Text in a CSP Application<br />

chapter in <strong>Using</strong> Caché Server Pages (CSP). If you are new to CSP, please read the<br />

other chapter before continuing in this book.<br />

For a simple demonstration of a localized CSP application, enter the following URI while Caché is<br />

running. Substitute your Caché Web server port number for 57772:<br />

http://localhost:57772/csp/samples/language.csp<br />

20.1.1 Localization Practices<br />

Caché supports the following process for localizing CSP application text:<br />

1. Developers determine where text strings are displayed in the application user interface.<br />

<strong>Using</strong> <strong>Zen</strong> 395


<strong>Zen</strong> Localization<br />

2. Developers create an XML message file that contains text strings in the original language.<br />

3. Developers import the XML into a Caché namespace.<br />

This adds new entries to the Message Dictionary in that namespace.<br />

4. Developers give the XML to a team of translators.<br />

5. Translators produce a new XML message file by substituting translated text for the original.<br />

6. Developers import the new XML into a Caché namespace.<br />

Translated and original texts coexist in the Message Dictionary.<br />

7. At runtime, the application chooses which text to display based on the browser default language.<br />

20.1.2 Message Dictionary<br />

A Message Dictionary is a simple database of text strings organized by domain name, language name,<br />

and message ID:<br />

• The text of each message is a string of up to 32K characters. A message may consist solely of<br />

text, or it may also contain one or more parameters specified by %1, %2, etc.<br />

• A domain name is any arbitrary string. It identifies a group of related text items, such as all<br />

messages for a specific application or page.<br />

• A language name is an all-lowercase language tag that conforms to RFC1766. It consists of one<br />

or more parts: a primary language tag (such as en or ja) optionally followed by a hyphen (-) and<br />

a secondary language tag (en-gb or ja-jp).<br />

• A message ID is any arbitrary string; it uniquely identifies a message. The message ID only needs<br />

to be unique within a domain. You may assign a message ID or allow Caché to assign one,<br />

depending on the conventions you use to create the message.<br />

Each user-defined namespace in Caché stores its Message Dictionary in a subscripted global called<br />

^CacheMsg. The order of subscripts in ^CacheMsg is domain, language, and message ID.<br />

20.1.3 $$$Text Macros<br />

The easiest way to create a Message Dictionary is to automatically generate Message Dictionary entries<br />

at compile time, by seeding the CSP class code with $$$Text macro calls. $$$Text automatically creates<br />

the message at compile time and generates the code that retrieves the message at runtime, as this topic<br />

explains.<br />

When it comes time to translate the application messages into another language, you can export the<br />

full list of messages for the original language out of the Message Dictionary by running an Export<br />

396 <strong>Using</strong> <strong>Zen</strong>


command. This generates a complete XML message file in the original language. See Managing a<br />

Message Dictionary in <strong>Using</strong> Caché Server Pages (CSP).<br />

The return value of a $$$Text macro is a %String. The correct $$$Text macro to use depends on the<br />

format you need for this output string:<br />

• $$$Text<br />

• $$$TextJS (applies JavaScript escaping to the $$$Text result)<br />

• $$$TextHTML (applies HTML escaping to the $$$Text result)<br />

The %String returned by $$$Text may be assigned to a variable, which you can use to represent the<br />

message in subsequent calls. For example:<br />

Set tmsg = $$$TextJS("Error saving production")<br />

&js<br />

Or, you can simply insert a $$$Text macro anywhere you need a string:<br />

&js<br />

20.1.3.1 $$$Text Arguments<br />

CSP Localization<br />

$$$Text has the arguments text, domain, and language as described in the following table. Only the<br />

first argument, text, is required.<br />

<strong>Using</strong> <strong>Zen</strong> 397


<strong>Zen</strong> Localization<br />

Argument<br />

text<br />

Description<br />

Non-empty string. text must be a literal string. It cannot use any type of<br />

expression syntax. The format used for text may be:<br />

"actualText"<br />

Or:<br />

"@textId@actualText"<br />

Where textId is a message ID and actualText is the text of the message.<br />

The string actualText may consist of any of the following items, separately<br />

or in combination:<br />

• Simple text, as permitted by the file format<br />

• Substitution arguments %1, %2, %3, or %4<br />

• HTML formatting<br />

• A string expression in Caché ObjectScript format<br />

If provided, the textId is used as the message ID. If @textId@ is not specified,<br />

Caché generates a new textId by calculating the 32–bit CRC (Cyclic<br />

Redundancy Check) of this text. If the textId is specified and a message<br />

already exists with this ID, the existing message is checked to see if it has<br />

the same text as actualText. If not, an error is reported.<br />

domain<br />

(Optional) A string specifying the domain for the new message. If not<br />

specified, domain defaults to the value of the DOMAIN class parameter at<br />

compile time and %response.Domain at runtime.<br />

398 <strong>Using</strong> <strong>Zen</strong>


CSP Localization<br />

Argument<br />

language<br />

Description<br />

(Optional) An RFC1766 code specifying the language. Caché converts<br />

this string to all-lowercase. If not specified, language defaults as follows:<br />

• At compile time: $$$DefaultLanguage.<br />

• At runtime: %response.Language, or if no value is defined for<br />

%response.Language then $$$DefaultLanguage.<br />

Tag-based CSP pages automatically acquire a value for<br />

%response.Language from browser settings, so it is available as a<br />

default language. This is not true for class-based CSP pages, which<br />

must explicitly set a value for %response.Language to use it as a<br />

default.<br />

You can assign a value to %response.Language by giving it the return<br />

value of the %Library.MessageDictionary class method MatchLanguage.<br />

Given a list of languages and a domain name, this method uses HTTP<br />

1.1 matching rules (RFC2616) to find the best-match language within<br />

the domain.<br />

20.1.3.2 $$$Text at Compile Time<br />

When you compile a class that contains calls to $$$Text, $$$TextJS, or $$$TextHTML macros, each<br />

call generates a message in the Message Dictionary, with text, message ID, domain, and language as<br />

provided by the macro arguments.<br />

20.1.3.3 $$$Text at Runtime<br />

If the message text contains arguments (%1, %2, %3, %4) you must specify the corresponding substitution<br />

text before displaying the text. Since $$$Text returns a string, you can use any string operation native<br />

to your coding language. For example, in JavaScript:<br />

var prompt = '#($$$TextHTML("Remove user %1 from this Role"))#';<br />

prompt = prompt.replace(/%1/g,member.userName);<br />

You can also input the $$$Text string into the first argument of the %response.FormatText method<br />

or a $$$FormatText macro. For details see Localization from Class Code in <strong>Using</strong> Caché Server Pages<br />

(CSP).<br />

<strong>Using</strong> <strong>Zen</strong> 399


<strong>Zen</strong> Localization<br />

20.2 <strong>Zen</strong> Localization<br />

<strong>Zen</strong> pages are CSP pages. All CSP localization practices also apply to <strong>Zen</strong> pages. However, <strong>Zen</strong> adds<br />

the following conventions to make localization even easier:<br />

• Any <strong>Zen</strong> property that has its ZENLOCALIZE parameter set to 1 (true) automatically generates<br />

a Message Dictionary entry. Caché generates the Message Dictionary using similar conventions<br />

as when you use textid="" in and other localizable CSP tags. That is:<br />

- The message text is the string value of the property<br />

- The message ID is the 32–bit CRC of the text<br />

- The domain takes the value of the DOMAIN class parameter<br />

- The language takes the value of the browser default language (at runtime)<br />

• The <strong>Zen</strong> datatype class, %ZEN.Datatype.caption, has a default value of 1 (true) for its ZENLOCAL-<br />

IZE parameter, so any property defined as having a type of %ZEN.Datatype.caption is automatically<br />

localized as described above.<br />

• For these conventions to work, the <strong>Zen</strong> page class that defines the property must provide a value<br />

for the DOMAIN class parameter.<br />

20.2.1 Localization for Built-In Components<br />

Essentially what happens when ZENLOCALIZE is true is that, when <strong>Zen</strong> generates the %CreatePage<br />

method from your description, <strong>Zen</strong> inserts the call to $$$Text on your behalf (without your<br />

needing to worry about setting the arguments properly). If you are using a component with a property<br />

that uses a <strong>Zen</strong> datatype with ZENLOCALIZE set to 1 (such as %ZEN.Datatype.caption), and you<br />

place this component within a element in XData Contents, and your page has a DOMAIN<br />

parameter value defined, then the code that <strong>Zen</strong> generates to set this property in %CreatePage automatically<br />

calls $$$Text. For example:<br />

<br />

Generates code like this in %CreatePage:<br />

Set bttn.caption = $$$Text("OK")<br />

On the other hand, if you programmatically build pages (without using ) there is no automatic<br />

localization of component properties, even if ZENLOCALIZE is true. In this case you must call $$$Text<br />

yourself.<br />

400 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Localization<br />

20.2.2 Localization for Custom Components<br />

If you are creating a new component, you can define properties that should be localized as datatype<br />

%ZEN.Datatype.caption:<br />

Property title As %ZEN.Datatype.caption;<br />

Within your component simply use ..title to refer to the property. You do not need $$$Text within<br />

your custom component code unless you have some static text that you wish to localize. Whenever a<br />

references your component, your property is automatically localized in the same way as builtin<br />

<strong>Zen</strong> components. For example:<br />

<br />

Generates code like this in %CreatePage:<br />

Set MyCmp = $$$Text("AAA")<br />

<strong>Using</strong> <strong>Zen</strong> 401


21<br />

<strong>Zen</strong> Reports<br />

<strong>Zen</strong> provides an extensible framework for specifying database reports in XHTML or PDF format.<br />

Report output in PDF format might look like the following sample.<br />

It takes three steps to generate <strong>Zen</strong> report output:<br />

<strong>Using</strong> <strong>Zen</strong> 403


<strong>Zen</strong> Reports<br />

1. The developer creates a <strong>Zen</strong> report class and, within it, provides two XML documents:<br />

• XData ReportDefinition describes the data<br />

• XData ReportDisplay describes the display<br />

2. The developer or end-user generates output by entering the report class URI in a browser, or by<br />

invoking the GenerateReport method from the command line or from within the application.<br />

The type of output must be specified:<br />

• XHTML can be viewed in a browser<br />

• PDF creates printer-friendly pages<br />

3. The report class guides the data and display information through one of the two processing<br />

sequences shown in the following figure: XHTML or PDF.<br />

How a <strong>Zen</strong> Report Class Produces a Report<br />

404 <strong>Using</strong> <strong>Zen</strong>


Building a Report<br />

The two main processing sequences for <strong>Zen</strong> reports are as follows:<br />

To XHTML<br />

To PDF<br />

For XHTML output, XData ReportDefinition causes a query to be run. <strong>Zen</strong> formats the data<br />

from this query as XML. Meanwhile, XData ReportDisplay generates an XSLT transformation<br />

called the To-HTML stylesheet. <strong>Zen</strong> applies this XSLT transformation to the XML file. The<br />

result is the XHTML output file.<br />

For PDF output, XData ReportDefinition causes a query to be run. <strong>Zen</strong> formats the data from<br />

this query as XML. Meanwhile, XData ReportDisplay generates an XSLT transformation<br />

called the To-XSLFO stylesheet. <strong>Zen</strong> sends this XSLT transformation and the XML file to<br />

a third-party rendering tool, which uses them to generate a report in XSL-FO format. The<br />

third-party tool then renders the XSL-FO as PDF.<br />

The next several topics in this chapter explain how to develop a <strong>Zen</strong> report class:<br />

• Building a Report<br />

• <strong>Zen</strong> Report Parameters<br />

• XData ReportDefinition<br />

• XData ReportDisplay, which may contain:<br />

- Layout and Display Elements<br />

- Stylesheet Control Elements<br />

The chapter then describes how to process the class to produce XHTML or PDF reports:<br />

• <strong>Zen</strong> Reports from a Web Browser<br />

• Configuring <strong>Zen</strong> for PDF Output<br />

• Troubleshooting <strong>Zen</strong> Reports<br />

• <strong>Zen</strong> Reports from a Command Line<br />

21.1 Building a Report<br />

This topic explains <strong>Zen</strong> report class structure by building a class in gradual steps.<br />

If you have a new Caché installation, you must first generate data records for the SAMPLES namespace.<br />

You only need to do this once per Caché installation. Enter the following URI in the browser:<br />

<strong>Using</strong> <strong>Zen</strong> 405


<strong>Zen</strong> Reports<br />

http://localhost:57772/csp/samples/ZENDemo.Home.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché.<br />

Now you may begin the exercise as follows:<br />

1. Start Caché Studio.<br />

2. Choose File > Change Namespace or F4.<br />

3. Choose the SAMPLES namespace.<br />

4.<br />

Choose File > New or Ctrl-N or the<br />

5. Select the Custom tab.<br />

6. Click the New <strong>Zen</strong> Report icon.<br />

icon.<br />

7. Click OK.<br />

The <strong>Zen</strong> Report Wizard presents the fields shown in the following table. For this exercise, enter<br />

the values shown in the right-hand column of the table.<br />

Field<br />

Package Name<br />

Class Name<br />

Application<br />

Report Name<br />

Description<br />

Click Next.<br />

Meaning<br />

The package that will<br />

contain the report class.<br />

The report class name.<br />

The package and class<br />

name of the application<br />

that this report belongs to.<br />

The logical name of this<br />

report within its<br />

application.<br />

Any text that you want to<br />

use to describe the report.<br />

Value to Enter<br />

MyApp<br />

ReportDemo<br />

MyReport<br />

Sample of building a new<br />

report.<br />

8. The wizard prompts you to enter an SQL query to provide data for the report. Type:<br />

SELECT ID,Customer,Num,SalesRep,SaleDate<br />

FROM ZENApp_Report.Invoice ORDER BY SalesRep,Customer<br />

Click Finish.<br />

The New Report Wizard creates and displays a <strong>Zen</strong> report page class with pre-defined parameter<br />

values and the XML blocks XData ReportDefinition and XData ReportDisplay.<br />

406 <strong>Using</strong> <strong>Zen</strong>


9. Find the following text in the XData ReportDefinition block. Place the cursor between this comment<br />

and the closing element:<br />

<br />

10. A report consists of one or more nested groupings. Define the first grouping inside the XData<br />

ReportDefinition by adding the following element at the cursor position, before :<br />

<br />

<br />

<br />

<br />

Building a Report<br />

11.<br />

12.<br />

Choose Build > Compile or Ctrl-F7 or the icon.<br />

Choose View > Web Page or the icon. If you have difficulty viewing the <strong>Zen</strong> report page from<br />

Studio, start a browser session and enter the class name as follows:<br />

http://localhost:57772/csp/samples/MyApp.ReportDemo.cls<br />

Where 57772 is the Web server port number that you have assigned to Caché.<br />

The XML view of your report data displays as follows. It has structure, but no content:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

13. Add an element to the within XData ReportDefinition:<br />

<br />

<br />

<br />

<br />

<br />

14. Compile the class and view the report. The XML output appears as follows. Each <br />

element now includes an attribute, name, whose value is the SalesRep field returned by the SQL<br />

query:<br />

<strong>Using</strong> <strong>Zen</strong> 407


<strong>Zen</strong> Reports<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

15. Add an element to the group within XData ReportDefinition:<br />

<br />

<br />

<br />

<br />

<br />

<br />

16. Compile the class and view the report. The XML output appears as follows. Each <br />

element now includes an element called . The value within is the sum of all the<br />

Num field values for the corresponding SalesRep field returned by the SQL query:<br />

<br />

<br />

<br />

833<br />

<br />

<br />

774<br />

<br />

<br />

983<br />

<br />

<br />

826<br />

<br />

<br />

824<br />

<br />

<br />

825<br />

<br />

<br />

17. Add more , , and elements within XData ReportDefinition:<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

408 <strong>Using</strong> <strong>Zen</strong>


18. Compile the class and view the report. The XML output now displays a much larger data set for<br />

each sales person. The aggregate elements , , and appear at the end of<br />

each record.<br />

19. Now that you have structured the report data as XML, you can specify how to display this data<br />

in XHTML or PDF format.<br />

Find the following text in the XData ReportDisplay block. Place the cursor between this comment<br />

and the closing element:<br />

<br />

20. At the cursor position, add a element to enclose the display items within the report. Within<br />

the place a that displays a title for the report. Also add the title attribute to the <br />

element to set the title of the browser window:<br />

<br />

<br />

Tutorial Sales Report<br />

<br />

<br />

21. Change the DEFAULTMODE class parameter value from "xml" to "html".<br />

22. Compile the class and view the report.<br />

23. Add a table to XData ReportDisplay as follows:<br />

<br />

<br />

Tutorial Sales Report<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Where:<br />

Building a Report<br />

• is a reference to the element in the generated<br />

XML.<br />

• is the syntax for referring to the attribute name.<br />

• is the syntax for referring to the element .<br />

<strong>Using</strong> <strong>Zen</strong> 409


<strong>Zen</strong> Reports<br />

24. Compile the class and view the report.<br />

25. Highlight the heading by formatting it using a pre-defined style class. Change the element in<br />

XData ReportDisplay as follows:<br />

Tutorial Sales Report<br />

26. Compile the class and view the report.<br />

27. Consider adding the following display modifications within XData ReportDisplay. Some of these<br />

changes affect style and layout; others add data to the display:<br />

<br />

<br />

Tutorial Sales Report<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

28. Compile the class and view the report.<br />

21.2 <strong>Zen</strong> Report Parameters<br />

A <strong>Zen</strong> report class may define the class parameters listed in the following table.<br />

410 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Report Parameters<br />

Report Class Parameters<br />

Class Parameter<br />

DATASOURCE<br />

Description<br />

(Optional) Identifies an XML document that contains the data<br />

for the <strong>Zen</strong> report. This string can be the URI of any valid XML<br />

document. Relative URIs are handled with respect to the current<br />

URI.<br />

If DATASOURCE is an empty string, the class generates its own<br />

XML document using the specification in its XData ReportDefinition<br />

block. If a <strong>Zen</strong> report class has both a non-empty, valid<br />

DATASOURCE string and an XData ReportDefinition block, the<br />

DATASOURCE parameter takes precedence over the XData<br />

block.<br />

The DATASOURCE string can refer to an XML document created<br />

by another <strong>Zen</strong> report class in the same namespace. Use the<br />

$MODE=xml query parameter to specify that you want to use the<br />

XML output from that class:<br />

Parameter DATASOURCE="MyApp.Report.cls$MODE=xml";<br />

DEFAULTMODE<br />

Default output mode for the report. This value is used only if the<br />

URI parameter $MODE is not specified. Possible values are:<br />

• "html" — Report display in XHTML format<br />

• "pdf" — Report display in PDF format<br />

• "tohtml" — To-HTML stylesheet in XSLT format<br />

• "toxslfo" — To-XSLFO stylesheet in XSLT format<br />

• "xml" — Report data in XML format<br />

• "xslfo" — Report pre-display in XSL-FO format<br />

If there is no DEFAULTMODE and no $MODE, the default is<br />

"html".<br />

<strong>Using</strong> <strong>Zen</strong> 411


<strong>Zen</strong> Reports<br />

Class Parameter<br />

HTMLSTYLESHEET<br />

Description<br />

Identifies the to-HTML stylesheet that controls XHTML output<br />

for the <strong>Zen</strong> report. This string can be the URI of any valid XSLT<br />

stylesheet. Relative URIs are handled with respect to the current<br />

URI.<br />

If HTMLSTYLESHEET is an empty string, the class generates<br />

a to-HTML stylesheet using the specification in its XData<br />

ReportDisplay block. If a <strong>Zen</strong> report class has both a non-empty,<br />

valid HTMLSTYLESHEET string and an XData ReportDisplay<br />

block, the HTMLSTYLESHEET parameter takes precedence<br />

over the XData block.<br />

The HTMLSTYLESHEET string can refer to a to-HTML<br />

stylesheet created by another <strong>Zen</strong> report class in the same<br />

namespace. Use the $MODE=tohtml query parameter to specify<br />

that you want to use the to-HTML output from that class:<br />

Parameter HTMLSTYLESHEET="MyApp.Report.cls$MODE=tohtml";<br />

REPORTNAME<br />

REPORTXMLNAMESPACE<br />

XSLFOSTYLESHEET<br />

Controls the filename suggested by the browser when you ask<br />

to save a report in XHTML or PDF format.<br />

(Optional) XML namespace to be used in the generated XML<br />

report.<br />

Identifies the to-XSLFO stylesheet that controls PDF output for<br />

the <strong>Zen</strong> report. This string can be the URI of any valid XSLT<br />

stylesheet. Relative URIs are handled with respect to the current<br />

URI.<br />

If XSLFOSTYLESHEET is an empty string, the class generates<br />

a to-XSLFO stylesheet using the specification in its XData<br />

ReportDisplay block. If a <strong>Zen</strong> report class has both a non-empty,<br />

valid XSLFOSTYLESHEET string and an XData ReportDisplay<br />

block, the XSLFOSTYLESHEET parameter takes precedence<br />

over the XData block.<br />

The XSLFOSTYLESHEET string can refer to a to-XSLFO<br />

stylesheet created by another <strong>Zen</strong> report class in the same<br />

namespace. Use the $MODE=toxslfo query parameter to<br />

specify that you want to use the to-XSLFO output from that class:<br />

Parameter HTMLSTYLESHEET="MyApp.Report.cls$MODE=toxslfo";<br />

412 <strong>Using</strong> <strong>Zen</strong>


XData ReportDefinition<br />

21.3 XData ReportDefinition<br />

The XData ReportDefinition block specifies the data to gather for the report. It also describes how to<br />

format this data as XML. An XData ReportDefinition block may contain references to the following<br />

variable:<br />

• %val — the value of the field attribute in the same element<br />

And may contain the following XML elements:<br />

• — Identifies the query that returns the data.<br />

Contains the following elements in any order or quantity:<br />

- — Writes an XML element to the output XML file<br />

- — Writes an XML attribute to the output XML file<br />

- — Calculates sums and averages for reporting purposes<br />

Contains 0 or 1 of the following:<br />

- — Groups items together so that operations can be performed on the group<br />

The following is a sample XData ReportDefinition block:<br />

XData ReportDefinition<br />

{<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

}<br />

You can omit or override the XData ReportDefinition block if you provide a valid value for the<br />

DATASOURCE class parameter. If you provide both, the DATASOURCE value takes precedence.<br />

<strong>Using</strong> <strong>Zen</strong> 413


<strong>Zen</strong> Reports<br />

You can also omit XData ReportDefinition if you only plan to use this <strong>Zen</strong> report class to generate<br />

XSLT stylesheets.<br />

21.3.1 The %val Variable<br />

%val is a variable that you can use only in an XData ReportDefinition block.<br />

You can use %val in the expression attribute for , , or . %val represents<br />

the value of the field from the field attribute in the same element. You can see this in the following<br />

example:<br />

<br />

Or in :<br />

<br />

also supports %val. You can use %val in a breakOnExpression attribute to represent the<br />

value of the field from the breakOnField value.<br />

21.3.2 <br />

The element is the top level container within an XData ReportDefinition block.<br />

Within an XData ReportDefinition block, a may contain multiple , ,<br />

and elements in any order, but without nesting them. A may contain one .<br />

Each may contain one . Only one may exist at each level of nesting within<br />

the .<br />

requires a name attribute and some combination of query attributes. supports the<br />

same attributes as .<br />

Important:<br />

There is a different element for use within an XData ReportDisplay block.<br />

21.3.3 <br />

The element is valid within a or in an XData ReportDefinition block.<br />

Each adds an XML element to the XML document. has the attributes listed in<br />

the following table.<br />

414 <strong>Using</strong> <strong>Zen</strong>


XData ReportDefinition<br />

Attribute<br />

expression<br />

Description<br />

(Optional) Can be used to process the field value before outputting it. The<br />

language of the expression must be Caché ObjectScript. Within the<br />

expression, the %val variable represents the field value. For example, in a<br />

<strong>Zen</strong> report class with a GetDisplayURL method:<br />

<br />

The expression attribute can be used without the field attribute to return<br />

static data such as the report run time:<br />

<br />

field<br />

name<br />

Specifies which resultset field to get the data from.<br />

Generates an XML element of this name in the output. An entry like this:<br />

<br />

Yields an XML element like this:<br />

July<br />

21.3.4 <br />

The element is valid within a or in an XData ReportDefinition block.<br />

works just like , but the data it captures is rendered as an attribute of the containing<br />

or element.<br />

21.3.5 <br />

The element may appear within a or . performs a calculation<br />

over every record in the resultset returned by the query for the XData ReportDefinition block.<br />

has the attributes listed in the following table.<br />

<strong>Using</strong> <strong>Zen</strong> 415


<strong>Zen</strong> Reports<br />

Attribute<br />

class<br />

method<br />

Description<br />

If the type is CLASS, the class attribute must specify the package and class<br />

name of a class that extends %ZEN.Report.CustomAggregate.<br />

You can create your own subclasses of %ZEN.Report.CustomAggregate, or<br />

there are several built-in aggregate classes that you can reference.<br />

If the type is CUSTOM, the method attribute must specify the name of a<br />

server-side method within the <strong>Zen</strong> report class. The method must have the<br />

following form:<br />

ClassMethod MyAgg(pMode As %String,<br />

pAccumValue As %String,<br />

pValue As %String,<br />

pCount As %Integer)<br />

As %String<br />

{<br />

Quit<br />

$Case(pMode,"Start":0,"Accum":pAccumValue+(pValue*2),"End":pAccumValue)<br />

}<br />

type<br />

Specifies which kind of aggregation to perform. Valid values include the following<br />

case-sensitive strings:<br />

• "SUM" — the sum of all values<br />

• "COUNT" — the total number of records<br />

• "AVG" — the average of all values<br />

• "MAX" — the maximum value in the set<br />

• "MIN" — the minimum value in the set<br />

• "CLASS" — (see the class attribute)<br />

• "CUSTOM" — (see the method attribute)<br />

21.3.5.1 Built-in Aggregate Classes<br />

The following are the built-in custom aggregate classes:<br />

• %ZEN.Report.Aggregate.CountDistinct<br />

The number of distinct values in a set of data, as opposed to a simple COUNT.<br />

• %ZEN.Report.Aggregate.Median<br />

The median of a set of numerical data, as opposed to a simple AVG (average). The median is a<br />

number with half of the data set of greater value than it, and half of lesser value.<br />

416 <strong>Using</strong> <strong>Zen</strong>


For a data set with an odd size, the median is a member of the data set. For a data set with an even<br />

size, the median is a value halfway between two members of the data set.<br />

• %ZEN.Report.Aggregate.Mode<br />

The statistical mode (most frequent observation) of a set of data.<br />

• %ZEN.Report.Aggregate.StDev<br />

The standard deviation of the values processed.<br />

XData ReportDefinition<br />

21.3.5.2 Creating a New Aggregate Class<br />

If you need a new type of aggregate, you can develop and use a custom aggregate class as follows:<br />

1. Subclass %ZEN.Report.CustomAggregate<br />

2. Override the following methods:<br />

• GetResult is invoked after every record has been processed to return the final value of the<br />

aggregate.<br />

• ProcessValue is called sequentially on each record returned by the report query or queries.<br />

3. Save and compile the class as myPackage.myClassName<br />

4. When referencing this calculation in the element, use these attributes:<br />

• type="CUSTOM"<br />

• class="myPackage.myClassName"<br />

The following example may be useful to you if you are creating your own aggregate class. This is the<br />

code for the built-in custom aggregate class %ZEN.Report.Aggregate.CountDistinct:<br />

<strong>Using</strong> <strong>Zen</strong> 417


<strong>Zen</strong> Reports<br />

/// Aggregate for counting the number of distinct values in a set of data<br />

Class %ZEN.Report.Aggregate.CountDistinct Extends %ZEN.Report.CustomAggregate<br />

{<br />

/// Array of values processed<br />

Property Values As array Of %String;<br />

/// Running count of distinct values processed<br />

Property Count As %Integer [ InitialExpression = 0 ];<br />

/// Processes each new value<br />

Method ProcessValue(pValue As %String) As %Status<br />

{<br />

If ..Values.GetAt(pValue) {<br />

// seen it already<br />

} Else {<br />

Do ..Values.SetAt(1,pValue)<br />

Set ..Count=..Count+1<br />

}<br />

}<br />

Quit $$$OK<br />

}<br />

/// Return the count of distinct values processsed<br />

Method GetResult() As %String<br />

{<br />

Quit ..Count<br />

}<br />

21.3.6 <br />

Within an XData ReportDefinition block, the element indicates that <strong>Zen</strong> should perform the<br />

same set of operations on all records from the resultset that match a specified criteria. If the <br />

specifies no criteria, <strong>Zen</strong> performs the operations on every record in the resultset. The elements<br />

contained within the element specify what to do. A may contain multiple ,<br />

, and elements in any order, but without nesting them.<br />

A may contain one . Each may contain one . Only one <br />

may exist at each level of nesting within the . You can see this convention in the sample XData<br />

ReportDefinition block.<br />

and have the general-purpose attributes listed in the following table.<br />

418 <strong>Using</strong> <strong>Zen</strong>


XData ReportDefinition<br />

Attribute<br />

breakOnExpression<br />

Description<br />

Provides an expression to apply to the value of the field specified<br />

by breakOnField. The language of the expression must be Caché<br />

ObjectScript. The %val variable gets the value of the raw data,<br />

and then the result of breakOnExpression string is returned.<br />

For example, suppose you want to group by month, and you have<br />

a method in the <strong>Zen</strong> report class called GetMonth which takes a<br />

date and returns the month.Then you could provide a like<br />

this:<br />

<br />

...<br />

<br />

breakOnField<br />

name<br />

The phrase breakOnField means “If you encounter this field, stop<br />

to examine its value.” All of the records in the resultset that contain<br />

the same value in the field specified by breakOnField are processed<br />

together.<br />

If the breakOnField attribute is omitted, or its value is left blank,<br />

the processes every record in the resultset in the same<br />

way.<br />

If you are breaking on a field, the query for the report should be<br />

ordered by that field. Field breaking examines the results sequentially<br />

and creates a break whenever the specified field changes.<br />

So if the query is not ordered by the field, a break may occur<br />

unexpectedly.<br />

The generates an XML element of this name in the output.<br />

If you do not provide a value for name, the generates a<br />

name based on the <strong>Zen</strong> report class name.<br />

A <strong>Zen</strong> report or may specify a query. The following table lists the attributes that<br />

support queries.<br />

<strong>Using</strong> <strong>Zen</strong> 419


<strong>Zen</strong> Reports<br />

Attribute<br />

OnCreateResultSet<br />

queryClass<br />

queryName<br />

runtimeMode<br />

sql<br />

Description<br />

(Optional) The name of a server-side callback method to call to<br />

create a %ResultSet object. The OnCreateResultSet value must be<br />

the name of a server-only method defined in the <strong>Zen</strong> report class.<br />

(Optional) The name of the class containing the query. You must<br />

also provide a value for queryName.<br />

(Optional) The name of the class query that will provide the<br />

%ResultSet for this list. You must also provide a value for<br />

queryClass.<br />

SQL runtime mode to apply to the %ResultSet object used to fetch<br />

results for this report. The default runtimeMode of 2 is appropriate<br />

for most cases and usually does not need to be changed. Possible<br />

values are: 0 for LOGICAL mode, 1 for ODBC mode, and 2 for<br />

DISPLAY mode.<br />

(Optional) Server-side SQL query to get contents of the <br />

list.<br />

This attribute has the underlying data type %ZEN.Datatype.sql. This<br />

means it cannot be accessed from the client. Its value is encrypted<br />

(using the current session key) when it is sent to the client. If this<br />

value is returned to the server, it is automatically decrypted. This<br />

makes it possible to place sensitive data on the client for future<br />

processing on the server, without letting a user view this data.<br />

For additional details, plus examples, see the <strong>Zen</strong> Tables chapter as follows:<br />

• How to use query attributes with or :<br />

- Specifying an SQL Query (sql)<br />

- Referencing a Class Query (queryClass, queryName)<br />

- <strong>Using</strong> a Callback Method (OnCreateResultSet)<br />

• How to provide elements within or :<br />

- Query Parameters<br />

420 <strong>Using</strong> <strong>Zen</strong>


XData ReportDisplay<br />

21.4 XData ReportDisplay<br />

The previous topic explained how to structure the XML data upon which the <strong>Zen</strong> report is based. This<br />

topic explains how to write a specification for displaying this data. The specification consists of an<br />

XData ReportDisplay block in the <strong>Zen</strong> report class.<br />

Styles in the XData ReportDisplay block are independent of the output format. At runtime, the choice<br />

of format depends on a parameter supplied by the caller in one of the following ways:<br />

• In a browser URI string (see Reports in a Web Browser)<br />

• At the Terminal command line (see <strong>Zen</strong> Reports from the Command Line)<br />

The exact value of the parameter depends on whether it is being used in the browser or at the command<br />

line. However, its meaning is the same in each environment. It instructs the <strong>Zen</strong> report class to create<br />

report output in one of the following formats:<br />

• XHTML — The <strong>Zen</strong> report class creates an XSLT stylesheet and uses this stylesheet to transforms<br />

its XML data into an XHTML report.<br />

• PDF — The <strong>Zen</strong> report class creates an XSLT stylesheet, then passes this XSLT stylesheet and<br />

the XML data file to a third-party rendering tool, which produces XSL-FO and then PDF output.<br />

An XData ReportDisplay block may contain the following XML elements:<br />

• — Identifies the title. Contains these elements (in the following order):<br />

- — general page characteristics, primarily for PDF output<br />

- — page headers, used in PDF and optionally in HTML<br />

- — page footers, used in PDF and optionally in HTML<br />

- — the container for elements that control:<br />

• Graphical layout (see Layout and Display Elements)<br />

• Style and appearance (see Stylesheet Control Elements)<br />

The following is a simple example that uses very few of the available elements:<br />

<strong>Using</strong> <strong>Zen</strong> 421


<strong>Zen</strong> Reports<br />

XData ReportDisplay<br />

{<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

Tests<br />

<br />

<br />

<br />

<br />

<br />

}<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

<br />

You can omit the XData ReportDisplay block entirely, if you provide a valid value for the HTML-<br />

STYLESHEET and XSLFOSTYLESHEET class parameters. For details, see <strong>Zen</strong> Report Parameters.<br />

If you provide both an XData ReportDisplay block and parameter values, the parameter values take<br />

precedence.<br />

You can also omit XData ReportDisplay if you only plan to use this <strong>Zen</strong> report class to generate XML<br />

data files.<br />

422 <strong>Using</strong> <strong>Zen</strong>


XData ReportDisplay<br />

21.4.1 Dimension and Size<br />

An XData ReportDisplay block allows you to specify sizes (widths, heights, lengths, etc.) in a variety<br />

of units, just as you would in HTML or XSL-FO syntax. 2in, 5cm, 12px, 14pt, 3em, or 75% are all<br />

valid sizes. Generally, <strong>Zen</strong> measures percentage values with respect to the containing element.<br />

21.4.2 <br />

The element is the top level container in an XData ReportDisplay block.<br />

Important:<br />

There is a different element for use within an XData ReportDefinition block.<br />

Within an XData ReportDisplay block, may contain the following elements only. It must<br />

contain them in the following order and quantities:<br />

• (0 or 1)<br />

• (0 or 1)<br />

• (0 or 1)<br />

• (1 is required)<br />

A element that appears in an XData ReportDisplay block has the attributes listed in the following<br />

table.<br />

Attribute<br />

name<br />

style<br />

title<br />

Description<br />

The report name, which should match the top-level element name in the XML<br />

data for the report.<br />

If the XData ReportDefinition block from the same <strong>Zen</strong> report class is used<br />

to generate this XML, then the name attribute for the element in<br />

XData ReportDisplay should match the name attribute for the element<br />

in XData ReportDefinition.<br />

If style="none", the standard <strong>Zen</strong> stylesheet is not rendered, otherwise it is.<br />

The standard stylesheet is a collection of available style classes that includes<br />

p.banner1, table.table1, td.table1, th.table1, ..., th.table6, as well as table, td,<br />

and th.grid.<br />

For more on style classes, see the element.<br />

The report title, used for items such as the PDF filename or XHTML page<br />

title.<br />

<strong>Using</strong> <strong>Zen</strong> 423


<strong>Zen</strong> Reports<br />

21.4.3 <br />

The element applies primarily to PDF output. specifies physical layout<br />

characteristics such as page dimensions and margins. can contain multiple ,<br />

, and elements for custom styling.<br />

The element can be omitted from a , even if PDF output is intended. The result<br />

in this case is an 8.5x11 inch page with 1.25–inch left and right margins and 1–inch top and bottom<br />

margins.<br />

If more than one element is included in the , all but the first are ignored.<br />

has the attributes listed in the following table.<br />

Attribute<br />

footerHeight<br />

headerHeight<br />

height<br />

marginBottom<br />

marginLeft<br />

Description<br />

Like headerHeight, but refers to the .<br />

HTML length value that specifies a block of empty space to be reserved<br />

beneath the top margin, but above the main body of the report.<br />

headerHeight should be specified if this report has a <br />

element indicating a header to appear on every page.<br />

HTML length value that specifies the page height.<br />

HTML length value that specifies the bottom margin<br />

HTML length value that specifies the left margin.The margin is contained<br />

within the width of the page, so the width of the available area of the<br />

page is:<br />

width - (marginLeft + marginRight)<br />

marginRight<br />

marginTop<br />

width<br />

HTML length value that specifies the right margin.<br />

HTML length value that specifies the top margin<br />

HTML length value that specifies the page width.<br />

21.4.3.1 <br />

The element renders style information into a CSS class in the XHTML report, and into<br />

equivalent XSLT stylesheet information for the PDF report.<br />

elements can only occur as children of . Multiple elements may be present.<br />

Each element has the attribute listed in the following table.<br />

424 <strong>Using</strong> <strong>Zen</strong>


XData ReportDisplay<br />

Attribute<br />

name<br />

Description<br />

Identifies a style class. Style class names are of the form tag.class, as in<br />

cascading style sheets (CSS). Possible names include:<br />

• table (referring to general table layout)<br />

• th (table header cells)<br />

• td (table cells)<br />

• a (links)<br />

• p (paragraphs)<br />

For more on style classes, see the class attribute as described in Layout<br />

and Display Elements.<br />

The element contains elements that specify the styling information for the class. <br />

can only occur as a child of . It specifies a piece of style information for that class. has<br />

the attributes listed in the following table.<br />

Attribute<br />

name<br />

value<br />

Description<br />

The attribute name. This corresponds to a CSS attribute name (color,<br />

background-color, font-size, font-family, width, etc). <strong>Zen</strong> simply passes the<br />

attributes on to CSS and XSL-FO, so the user can specify anything; it<br />

is up to the browser or PDF rendering tool to be able to interpret the attribute.<br />

The value to assign to the attribute.<br />

To provide the equivalent of the CSS document fragment given here:<br />

th.myTable {<br />

background-color: blue;<br />

color: white;<br />

}<br />

The following element is needed:<br />

<br />

<br />

<br />

<br />

21.4.3.2 <br />

The element applies to XHTML output only. When producing the XSLT stylesheet for<br />

PDF output, the class simply ignores any elements.<br />

<strong>Using</strong> <strong>Zen</strong> 425


<strong>Zen</strong> Reports<br />

Multiple elements may be present within a element. Each <br />

element has has the attribute listed in the following table.<br />

Attribute<br />

href<br />

Description<br />

URI of an external CSS stylesheet to include in the HTML stylesheet.<br />

The href string can be a comma-delimited list of URIs, and each will be<br />

included; this the same as providing multiple elements.<br />

Some browsers struggle when the file referenced does not end in .css.<br />

21.4.3.3 <br />

The element applies to the XSLT stylesheet for PDF output only. When producing the<br />

HTML version of the report, the class simply ignores any elements.<br />

Multiple elements may be present within a element. Each <br />

element has the attribute listed in the following table.<br />

Attribute<br />

href<br />

Description<br />

Filename of an external XSLT file to include in the to-XSLFO stylesheet.<br />

This feature is potentially very powerful, but XSLT can be difficult to write.<br />

In practice, the main purpose of the element is for the external<br />

XSLT stylesheet to contain elements, which can do the<br />

same work as CSS classes.<br />

To continue the previous example, to import the th.myTable class from external files, the<br />

element would look something like this:<br />

<br />

<br />

<br />

<br />

With myStyle.css containing:<br />

th.myTable {<br />

background-color: blue;<br />

color: white;<br />

}<br />

And myStyle.xsl containing:<br />

<br />

blue<br />

white<br />

<br />

426 <strong>Using</strong> <strong>Zen</strong>


Layout and Display Elements<br />

21.4.4 <br />

The element, if present in the , must occur before the element.<br />

can contain the same layout and display elements as , but everything contained<br />

within is rendered in the blank space provided by the element headerHeight<br />

attribute.<br />

XHTML reports do not support page-by-page headers, so in XHTML reports the contents of <br />

are simply rendered at the beginning of the report.<br />

21.4.5 <br />

The element, if present in the , must occur before the element.<br />

is like . However, elements are not displayed in XHTML<br />

reports.<br />

21.4.6 <br />

The element is the required child of . It has no attributes, but contains the bulk of the<br />

report information. contains elements that control:<br />

• Graphical layout — see Layout and Display Elements<br />

• Style and appearance — see Stylesheet Control Elements<br />

21.5 Layout and Display Elements<br />

This topic describes the elements that display the visual content of the report. Any of these elements<br />

may be a child of , , , or . The elements are:<br />

• — Bar chart<br />

• — Group of items for a table row or column<br />

• — Group of items for a page footer<br />

• — Group of items for repeated actions<br />

• — Group of items for a page header<br />

• — Image<br />

• — Data value<br />

<strong>Using</strong> <strong>Zen</strong> 427


<strong>Zen</strong> Reports<br />

• — Horizontal line<br />

• — Line chart<br />

• — Bulleted or numbered list<br />

• — Raw text of any length<br />

• — Page break<br />

• — Pie chart<br />

• — Table<br />

Each of these elements has the three attributes described in the following table. It may have other<br />

attributes also; the next several topics describe them.<br />

Report Display Attributes<br />

Attribute<br />

class<br />

Description<br />

CSS style class to apply to the element. Style classes are defined by the<br />

element, and some are given by the standard style sheet.<br />

When specifying a value for the class attribute, do not include the element<br />

name that is given when creating the class. For example, if you have a style<br />

class named table.myTable that you want to use, in the specify:<br />

<br />

Parent elements propagate their class attribute value to children that do not<br />

have a class specified. So if you define table.myTable, th.myTable, and<br />

td.myTable, you only need to give the element a class attribute.You<br />

can even put a class attribute on the element to give a class for<br />

every element in the report (at least, for those that do not override it with a<br />

class attribute of their own).<br />

style<br />

Similar to the style attribute in CSS, this attribute may provide a semicolondelimited<br />

list of attribute:value pairs. For example:<br />

style="fill: yellow; font-size: 6pt ;"<br />

Information contained within the style attribute takes precedence over style<br />

information given by the class.<br />

width<br />

HTML length value that defines the element’s width. The exact meaning<br />

depend on the individual element. If widths are omitted, the PDF rendering<br />

tool can produce unexpected results.<br />

428 <strong>Using</strong> <strong>Zen</strong>


Layout and Display Elements<br />

21.5.1 <br />

The element renders all of its child elements sequentially. It can be used anywhere in the<br />

as a kind of spanning element, but it is most useful as a container within a . In general,<br />

a treats every child element as a new row or column, so the element can be used to<br />

group multiple elements into a single row or column.<br />

The element may contain any of the same common display elements as .<br />

has the common display attributes style, width, and class.<br />

21.5.2 <br />

Within an XData ReportDisplay block, the element allows the <strong>Zen</strong> report class to respond to<br />

the hierarchically structured data that is typical of XML.<br />

Important:<br />

There is a different element for use within an XData ReportDefinition block.<br />

is a display element, so has the common display attributes style, width, and class.<br />

also has the attributes listed in the following table.<br />

Attribute<br />

line<br />

Description<br />

HTML length value that specifies the thickness of the line to be drawn<br />

between each iteration of the group. If line is 0, no line is drawn.<br />

<strong>Using</strong> <strong>Zen</strong> 429


<strong>Zen</strong> Reports<br />

Attribute<br />

name<br />

Description<br />

Required. displays the contents of each element in the XML data<br />

whose name matches this attribute. So if your XML data contains<br />

elements, your XData ReportDisplay block could contain:<br />

...<br />

The elements within the container determine how the display<br />

handles the data within the container. can contain<br />

any of the common display elements listed at the beginning of this topic.<br />

elements can be nested. Suppose each elements<br />

contains multiple elements. To specify how to display each sale<br />

within the display for each sales representative, you would provide something<br />

like:<br />

<br />

<br />

...<br />

<br />

...<br />

<br />

To display a group as a table, see the group attribute of .<br />

pagebreak<br />

If true, put a page break after each iteration of the group.<br />

This attribute has the underlying data type %ZEN.Datatype.boolean. It has the<br />

value "true" or "false" in XData Contents, 1 or 0 in server-side code, true or<br />

false in client-side code. See Datatype Classes.<br />

21.5.3 and <br />

The and elements are simple containers used for clarity, but they can be useful to<br />

organize style within the report. Each can propagate its class attribute to its children.<br />

and have no attributes in addition to the common display attributes style, width,<br />

and class.<br />

21.5.4 <br />

The element inserts an image into the report.<br />

In addition to the common display attributes style, width, and class, has the attributes listed in<br />

the following table.<br />

430 <strong>Using</strong> <strong>Zen</strong>


Layout and Display Elements<br />

Attribute<br />

height<br />

src<br />

width<br />

Description<br />

HTML length value that specifies the image height.<br />

URI for source of the image. If the src attribute begins with an exclamation<br />

point, it is interpreted as an XPath expression just as in the field attribute of<br />

the element. This allows you to dynamically generate URIs within<br />

the XML data, and then use these customized URIs as the image source.<br />

When using ! to dynamically generate the image URI, the resulting string<br />

must be an absolute URI or it will not appear in the PDF report.<br />

HTML length value that specifies the image width.<br />

21.5.5 <br />

The element outputs literal values or data from the XML into the report. must have<br />

exactly one of its value, field, or special attributes specified.<br />

In addition to the common display attributes style, width, and class, has the attributes listed in<br />

the following table.<br />

Attribute<br />

field<br />

Description<br />

If the field attribute is specified, the renders the value of that<br />

field in the XML data. field is actually used as an XPath expression, so<br />

if you have the data:<br />

MegaPlex<br />

Systems<br />

To get the value of the id attribute you need the XPath expression:<br />

field= "@id"<br />

Whereas to obtain the value of the element you need the<br />

XPath expression:<br />

field="customer"<br />

The field attribute is interpreted with respect to the current <br />

matched. For an within , only<br />

attributes and children of are available.<br />

formatNumber<br />

String specifying the number format to use. This string uses the same<br />

conventions as the XSLT format-number function, such as ###.# for<br />

a three-digit number with one decimal place.<br />

<strong>Using</strong> <strong>Zen</strong> 431


<strong>Zen</strong> Reports<br />

Attribute<br />

link<br />

special<br />

Description<br />

Optional hyperlink to place around the item’s data. If the link attribute<br />

begins with an exclamation point, it is interpreted as an XPath<br />

expression just as in the field attribute. This allows you to dynamically<br />

generate URIs within the XML data, and then use these customized<br />

URIs in the display. If link is specified, the item’s style class will use the<br />

"a" option.<br />

If the special attribute is specified, the renders a pre-defined<br />

piece of dynamic data. Possible values for special are:<br />

• number — gives the record number within the group.<br />

• page-number — inserts the page number within a PDF report. Is<br />

rendered as '##' in XHTML.<br />

• page-count — inserts the number of pages within a PDF report. It<br />

is rendered as '##' in XHTML.<br />

• page-number-of — inserts the page number in the form '2 of 18'. It<br />

is rendered as '## of ##' in XHTML.<br />

• page-number-/ — inserts the page number in the form '2/18'. It is<br />

rendered as '##/##' in XHTML.<br />

References to the total page count can be slow in extremely large PDF<br />

reports. If speed is essential and you run into problems with speed,<br />

avoid page-count, page-number-of, and page-number-/.<br />

value<br />

If the value attribute is specified, the renders it as a literal value.<br />

21.5.6 <br />

The element inserts a line break into the report. This can either be a visible horizontal line or<br />

an empty line break.<br />

In addition to the common display attributes style, width, and class, has the attributes listed in<br />

the following table.<br />

Attribute<br />

align<br />

color<br />

Description<br />

Alignment within the report page. Possible values are "left", "right", and<br />

"center".<br />

CSS color value that specifies the line color. color only applies to solid or<br />

dashed lines<br />

432 <strong>Using</strong> <strong>Zen</strong>


Layout and Display Elements<br />

Attribute<br />

count<br />

length<br />

lineHeight<br />

pattern<br />

thickness<br />

Description<br />

The number of line breaks to draw.This is the same as repeating the <br />

element.<br />

HTML length value that specifies the line length. length only applies to solid<br />

or dashed lines.<br />

HTML length value that specifies how much space to leave for displaying<br />

the line. This is not the same as the line thickness when pattern is "solid"<br />

or "dashed". lineHeight applies to "empty" lines as well.<br />

Despite using this attribute, line spacing can vary between XHTML and<br />

XSL-FO (that is, PDF). This can be overcome using and elements.<br />

Possible values are "empty", "solid", and "dashed"<br />

HTML length value that specifies the line thickness. The default value is<br />

1px. thickness only applies to solid or dashed lines.<br />

21.5.7 <br />

The element is used to display an itemized or ordered list within a <strong>Zen</strong> report.<br />

The style attribute on the applies to its bullets or numbers.<br />

In addition to the common display attributes style, width, and class, has the attributes listed in<br />

the following table.<br />

Attribute<br />

group<br />

image<br />

startvalue<br />

type<br />

Description<br />

Required. group identifies the entry that provides the data for this<br />

list. The group value in must match the name value of some <br />

in XData ReportDefinition.<br />

The URI of an image to use as a custom bullet. If you provide an image<br />

value, the type attribute is ignored.<br />

The first number value for ordered lists. startvalue is always specified as an<br />

integer. If type is "A" and startvalue is "3", the first element in the list is<br />

labeled "C".<br />

The bullet or numbering style to use for list items. Possible values are:<br />

"none", "circle", "square", "disc", "1", "A", "a", "I", "i". PDF reports do not<br />

support "square" or "circle".<br />

<strong>Using</strong> <strong>Zen</strong> 433


<strong>Zen</strong> Reports<br />

21.5.8 <br />

The element renders a large block of static content. It treats its contents as raw text and uses the<br />

"p" option for its style class.<br />

has no attributes in addition to the common display attributes style, width, and class.<br />

21.5.9 <br />

The element inserts a page break in PDF output. It inserts a dashed line in the XHTML<br />

report on screen, and causes a page break when you print the XHTML report.<br />

21.5.10 <br />

The element outputs a table into the report.<br />

In addition to the common display attributes style, width, and class, has the attributes listed<br />

in the following table.<br />

Attribute<br />

align<br />

altcolor<br />

group<br />

Description<br />

Aligns the table within the report. Possible values are "left," "right," and<br />

"center".<br />

CSS color value that specifies the background color of the alternate rows<br />

(2, 4, 6, etc.).This is only possible when orient is "col" and group is specified.<br />

A table can be used to display a group of data. If the group attribute is<br />

specified, the table displays a row or column in the table for each item in<br />

the group. If no group is specified, there is only one row or column in the<br />

table (plus an optional header and optional footer row or column).<br />

434 <strong>Using</strong> <strong>Zen</strong>


Layout and Display Elements<br />

Attribute<br />

layout<br />

Description<br />

Possible layout values are "auto" and "fixed". For PDF output, the XEP<br />

rendering tool supports both "auto" and "fixed" formats. FOP supports "fixed"<br />

only.<br />

When layout is "fixed", it is important that you specify a width for each column.<br />

The code produces a good result from minimal width information, but<br />

you can gain closer control as follows:<br />

• If orient is "col," then each child of the table class should have a width<br />

attribute specified.<br />

• If orient is "row", then only one child of the table needs to have its widths<br />

specified. However, if that element within the table has a or<br />

child element to define a header column or footer column,<br />

it is necessary that these elements also specify their width.<br />

orient<br />

Each element contained within the table is treated as either a row or column,<br />

depending on the value of the orient attribute. If orient is "row," each child<br />

element of table will be placed in a new row. Similarly, if orient is "col" each<br />

child element will be placed in a new column. Possible values are "row"<br />

and "col". The default is "col".<br />

Every cell the table renders uses the "td" option for its style class, except for the header cells, which<br />

use "th".<br />

21.5.10.1 <br />

To include a caption for a row or column of the table, an element within a table can contain a <br />

element.<br />

The element works just like , and has the same attributes. When you place it as a<br />

child of an element within a table, it indicates that that row or column has a header, which it gets from<br />

the value of the element.<br />

When you have nested tables, it is possible for the inner table to have element within it, but<br />

that does not mean the is something for that table to display. It actually refers to giving the<br />

inner table a caption within the outer table.<br />

21.5.10.2 <br />

The element is the same as , except that it creates a footer for the row or column.<br />

<strong>Using</strong> <strong>Zen</strong> 435


<strong>Zen</strong> Reports<br />

21.6 Charts in <strong>Zen</strong> Reports<br />

Important:<br />

Like <strong>Zen</strong> Charts, charts in <strong>Zen</strong> reports use SVG for graphics. Support for SVG is built<br />

into Firefox 1.5 or later. If you are using Internet Explorer 6.0 or later, you must<br />

download the free SVG Viewer from Adobe to use charts in <strong>Zen</strong> reports.<br />

The syntax for placing charts in <strong>Zen</strong> reports is identical to the syntax for placing charts on <strong>Zen</strong> pages,<br />

with exceptions as noted in this topic. <strong>Zen</strong> reports support the , and <br />

elements only. <strong>Zen</strong> reports support chartPivot, but not chartStacked. does not support<br />

markers or filled line charts in <strong>Zen</strong> reports. Also, <strong>Zen</strong> report charts are not interactive.<br />

When used in <strong>Zen</strong> reports, the , and elements support the following<br />

attributes:<br />

Attribute<br />

<strong>Zen</strong> report<br />

attributes<br />

Chart<br />

attributes<br />

dataFields<br />

dataGroup<br />

seriesColors<br />

seriesCount<br />

Description<br />

General-purpose report display attributes: style, width, and class.<br />

General-purpose attributes that apply to any chart (see <strong>Zen</strong> Charts) plus<br />

the unique attributes that apply to , or .<br />

All charts: Comma-delimited list of fields to acquire data from. If a<br />

dataGroup is also provided, only the first data field in dataFields is used.<br />

Pie charts: A pie chart looks at the first field specified by dataFields and<br />

totals the value that each series has for this field. Each series then gets<br />

a slice proportional to its percentage of the total for this field.<br />

All charts: Specifies the group that provides the data elements for the<br />

chart.<br />

Pie charts: If dataGroup is specified, the pie chart determines the value<br />

for a series by summing the dataFields for each element in the<br />

dataGroup.<br />

Comma-delimited list of CSS color values used for data series. The<br />

colors can be acquired dynamically by using the form "!fieldname".<br />

Number of data series to display on this chart. If "", this is computed<br />

automatically from the chart’s data source.<br />

436 <strong>Using</strong> <strong>Zen</strong>


Stylesheet Control Elements<br />

Attribute<br />

seriesGroup<br />

seriesNames<br />

seriesSize<br />

Description<br />

All charts: The group that provides the list of series for the chart.<br />

Pie charts: seriesGroup is required. If series were specified statically,<br />

the series would be looking at the same data, and so the pie chart would<br />

be divided evenly no matter what.<br />

Comma-delimited list of names used to label each data series in the<br />

legend box. Series names can be acquired dynamically by beginning<br />

the value with a ! character. If seriesGroup is provided, only the first<br />

series name field is considered.<br />

Number of items within each data series to display on this chart. If<br />

omitted, <strong>Zen</strong> computes this number automatically from the chart’s data<br />

source.<br />

A or in a <strong>Zen</strong> report may contain and elements. When used<br />

in <strong>Zen</strong> reports, and support the following attributes:<br />

Attribute<br />

Axis<br />

attributes<br />

labelValues<br />

Description<br />

General-purpose attributes for chart axes.<br />

All charts: Comma-delimited list of label values of category axes. If left<br />

blank, the category number is used.<br />

Pie charts: labelValues cannot be specified on the chart, as pie charts<br />

do not have axes.<br />

21.7 Stylesheet Control Elements<br />

The following elements are valid anywhere within the element of an XData ReportDisplay<br />

block.<br />

21.7.1 <br />

The element can contain the same common display elements as , but everything contained<br />

within is rendered in the XSL-FO (that is, PDF) report only.<br />

is useful for correcting issues where the XHTML report and PDF report do not look alike due to<br />

inherent page differences, such as page breaks.<br />

<strong>Using</strong> <strong>Zen</strong> 437


<strong>Zen</strong> Reports<br />

21.7.2 <br />

The element is similar to , but renders its contents in the XHTML report only.<br />

21.7.3 <br />

The element writes directly to the stylesheet, instead of to the report.<br />

The element is a common display element, in the sense that it may legally appear anywhere<br />

within a or element. However, can be most useful within<br />

or . For example:<br />

<br />

<br />

This is HTML! ]]><br />

<br />

<br />

<br />

<br />

This is XSL-FO ]]><br />

<br />

<br />

21.8 <strong>Zen</strong> Reports from a Web Browser<br />

The XHTML and PDF reports can be viewed in a browser by entering the URI of the <strong>Zen</strong> report .cls<br />

file. To specify the output type, use a $MODE parameter in the query string. In the following examples,<br />

57772 is the port assigned to the Caché server:<br />

• To view the HTML report:<br />

http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=html<br />

The report displays in HTML format.<br />

• To view the PDF report, first use the instructions in Configuring <strong>Zen</strong> for PDF Output, then provide<br />

the following URI:<br />

http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=pdf<br />

The report displays in PDF format. Depending on your settings, the browser might first prompt<br />

you to save the file. If so, click Save to view the PDF.<br />

• To view raw data for a report in XML format:<br />

http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=xml<br />

Colorized XML displays in the browser.<br />

438 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Reports from a Web Browser<br />

You can override the current DATASOURCE setting for the report class by providing a $DATA-<br />

SOURCE parameter in the URI.<br />

Note:<br />

The examples above use 57772, the default port number assigned to the Caché server. The<br />

port number in your configuration might be different. You can double-check the port number<br />

by navigating to the System Management Portal [Home] > [Configuration] > [Memory and<br />

Startup] page.<br />

21.8.1 Sample XHTML Output<br />

<strong>Using</strong> <strong>Zen</strong> 439


<strong>Zen</strong> Reports<br />

21.8.2 Sample XML Data View<br />

21.9 Configuring <strong>Zen</strong> for PDF Output<br />

When you load a <strong>Zen</strong> report class into a browser with a request to view the output as PDF, Caché calls<br />

out to the command line to run a third-party PDF rendering tool. The rendering tool applies the XSLT<br />

stylesheet to the XML data to transform the XML into XSL-FO. Finally, the tool transforms the XSL-<br />

FO into PDF.<br />

This works only if you have performed the required configuration steps, as follows:<br />

1. Install an XSL-FO to PDF rendering tool. Two of the available options are:<br />

• An open source project from Apache called FOP. You can download it from the following<br />

Web site:<br />

http://xmlgraphics.apache.org/fop<br />

To install, simply extract the files from the kit.<br />

440 <strong>Using</strong> <strong>Zen</strong>


• The XEP product from RenderX. You can download a free trial version that produces a<br />

RenderX watermark on each output page, or you can buy the XEP product. See this Web site<br />

for details:<br />

http://www.renderx.com/tools/xep.html<br />

To install, follow the instructions in the kit.<br />

2. Set the Caché global ^%SYS("zenreport","transformerpath") to location of the batch<br />

file or shell script that calls the rendering tool. Once you have installed FOP or XEP, this file is<br />

already present on your system. Find its location, then set the global accordingly:<br />

• For FOP, something like:<br />

Set ^%SYS("zenreport","transformerpath")="C:\fop-0.92beta\fop.bat"<br />

• Or similarly, for XEP:<br />

Set ^%SYS("zenreport","transformerpath")="C:\XEP\XEP.bat"<br />

Troubleshooting <strong>Zen</strong> Reports<br />

3. (Optional) You can create custom configuration files for FOP as described in:<br />

http://xmlgraphics.apache.org/fop/0.92/configuration.html<br />

If you want the Caché callout to FOP to use a custom configuration file, you can set the global<br />

^%SYS("zenreport","transformerconfig") to the path of the configuration file. Configuration<br />

files are important for adding fonts to FOP. You must first create font metrics, and then<br />

register them with FOP. The process is described on the FOP Web site at:<br />

http://xmlgraphics.apache.org/fop/0.92/fonts.html<br />

Note:<br />

PDF rendering can consume a lot of memory. If you run into trouble, you might want to<br />

modify the FOP.bat or XEP.bat file to increase the amount of memory available to the Java<br />

Virtual Machine. The respective products provide documentation that explains how to do<br />

this.<br />

21.10 Troubleshooting <strong>Zen</strong> Reports<br />

When specifying $MODE=html or $MODE=pdf you can also set the query parameter $LOG=1. This<br />

allows you to view the output of the transformation from XML to XHTML or the transformation from<br />

XML via XSLT to XSL-FO to PDF, respectively. This information can be useful when the transformation<br />

fails. For example:<br />

http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=pdf&$LOG=1<br />

<strong>Using</strong> <strong>Zen</strong> 441


<strong>Zen</strong> Reports<br />

Where 57772 is the port number assigned to the Caché server.<br />

XSL-FO to PDF Transformation Log<br />

Note:<br />

Syntax errors in ReportDisplay are sometimes reported as FOP errors without being caught<br />

on the Caché side. $LOG=1 can be useful for exploring this type of bug.<br />

You can also display diagnostic information for a <strong>Zen</strong> report by providing special values for the<br />

$MODE query parameter when you supply the .cls URI to the browser. For example:<br />

• To view the XSLT stylesheet that turns XML into XHTML:<br />

http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=tohtml<br />

• To view the XSLT stylesheet that turns XML into XSL-FO:<br />

http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=toxslfo<br />

• To view the XSL-FO stylesheet before PDF rendering:<br />

http://localhost:57772/csp/myPath/myApp.myReport.cls$MODE=xslfo<br />

Note:<br />

The examples above use 57772, the default port number assigned to the Caché server. The<br />

port number in your configuration might be different. You can double-check the port number<br />

by navigating to the System Management Portal [Home] > [Configuration] > [Memory and<br />

Startup] page.<br />

442 <strong>Using</strong> <strong>Zen</strong>


XSL-FO Prior to PDF Rendering<br />

<strong>Zen</strong> Reports from a Command Line<br />

21.11 <strong>Zen</strong> Reports from a Command Line<br />

You can run a <strong>Zen</strong> report from the Terminal command line as follows:<br />

1. Change to the namespace containing the <strong>Zen</strong> report class:<br />

ZN "mySpace"<br />

2. Create an instance of the <strong>Zen</strong> report class:<br />

Set report=##class(myPackage.myClassName).%New()<br />

3. Run the report:<br />

Do report.GenerateReport("C:\Temp\mySample.pdf",2)<br />

Where:<br />

• C:\Temp\mySample.pdf is the pathname of the output file<br />

• 2 is an integer that tells <strong>Zen</strong> which type of report output to generate.<br />

Possible values include:<br />

- 0 — XML<br />

- 1 — XHTML<br />

<strong>Using</strong> <strong>Zen</strong> 443


<strong>Zen</strong> Reports<br />

- 2 — PDF. This works only if you have already used the instructions in the topic Configuring<br />

<strong>Zen</strong> for PDF Output.<br />

And for debugging purposes:<br />

- 3 — To-HTML stylesheet<br />

- 4 — To-XSLFO stylesheet<br />

• You may also provide an optional third parameter value of 1 (true):<br />

Do report.GenerateReport("C:\Temp\mySamplePDF.log",2,1)<br />

If so, the output file contains the transformation log rather than the report. This log is similar<br />

to the result in the browser when you supply the query parameter $LOG=1.<br />

444 <strong>Using</strong> <strong>Zen</strong>


22<br />

<strong>Zen</strong> Wizards<br />

This chapter describes the Caché Studio wizards that <strong>Zen</strong> provides:<br />

• Wizards for creating new application, component, page, or report classes.<br />

• Studio Assist (word completion) to help you rapidly add components to page classes.<br />

• Wizards for adding charts, elements, methods, and styles to page classes.<br />

22.1 New <strong>Zen</strong> Application Wizard<br />

Note:<br />

For background information, see <strong>Zen</strong> Application Concepts and <strong>Zen</strong> Application Programming.<br />

The <strong>Zen</strong> Tutorial chapter provides a sample New <strong>Zen</strong> Application Wizard session in the topic<br />

Creating a <strong>Zen</strong> Application.<br />

You can use the New <strong>Zen</strong> Application Wizard as follows:<br />

1. Start Studio.<br />

2.<br />

Choose File > New or Ctrl-N or the icon.<br />

3. Click the Custom tab.<br />

4. Click the New <strong>Zen</strong> Application icon.<br />

5. Click OK. The <strong>Zen</strong> Application Wizard dialog displays.<br />

6. Enter data in the following fields:<br />

• Package Name — Package that will contain the new application class.<br />

• Class Name — Class name of the new application class.<br />

<strong>Using</strong> <strong>Zen</strong> 445


<strong>Zen</strong> Wizards<br />

• Application Name — Logical name of the application.<br />

• Description — Any text that you want to use to describe the application.<br />

7. Click Finish. The dialog closes and your new <strong>Zen</strong> application class displays in Studio.<br />

8. Modify the <strong>Zen</strong> application class as desired.<br />

To supply style definitions that apply to all pages in this application, use the <strong>Zen</strong> Style Wizard to<br />

edit XData Style or set the CSSINCLUDES class parameter.<br />

9.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

icon.<br />

22.2 New <strong>Zen</strong> Component Wizard<br />

Note:<br />

For background information, see Custom Components.<br />

You can use the New <strong>Zen</strong> Component Wizard as follows:<br />

1. Start Studio.<br />

2.<br />

Choose File > New or Ctrl-N or the<br />

3. Click the Custom tab.<br />

4. Click the New <strong>Zen</strong> Component icon.<br />

icon.<br />

5. Click OK. The <strong>Zen</strong> Component Wizard dialog displays.<br />

6. Enter data in the following fields:<br />

• Package Name — Package that will contain the new component class.<br />

• Class Name — Class name of the new component class.<br />

• Type — Choose a parent class for the component:<br />

- component — See Creating Custom Components<br />

- composite — See Building Composite Components<br />

- control — See <strong>Zen</strong> Controls and Custom Components<br />

- svgComponent — See <strong>Zen</strong> and SVG and Creating a Custom Meter<br />

• XML Namespace — If the component is a composite, you must reference this namespace when<br />

you place the component on a <strong>Zen</strong> page, using the syntax . A<br />

446 <strong>Using</strong> <strong>Zen</strong>


namespace also helps to organize other types of custom component; see the chapter Custom<br />

Components, topic XML Namespace.<br />

• Description — Any text that you want to use to describe the component.<br />

7. Click Finish. The dialog closes and your new <strong>Zen</strong> component class displays in Studio.<br />

8. Modify the <strong>Zen</strong> component class as desired:<br />

New <strong>Zen</strong> Page Wizard<br />

• Be sure to implement the %DrawHTML method. The wizard provides a template for this<br />

method in the class.<br />

• If you want to supply style definitions for the custom component, consult the chapter Custom<br />

Components, topic Custom Style. You can use the <strong>Zen</strong> Style Wizard to add style definitions.<br />

9.<br />

Choose Build > Compile or Ctrl-F7 or the<br />

icon.<br />

22.3 New <strong>Zen</strong> Page Wizard<br />

Note:<br />

For background information, see <strong>Zen</strong> Application Concepts and <strong>Zen</strong> Application Programming.<br />

The <strong>Zen</strong> Tutorial chapter provides a sample New <strong>Zen</strong> Page Wizard session in the topic Creating<br />

a <strong>Zen</strong> Page.<br />

You can use the New <strong>Zen</strong> Page Wizard as follows:<br />

1. Start Studio.<br />

2.<br />

Choose File > New or Ctrl-N or the icon.<br />

3. Click the Custom tab.<br />

4. Click the New <strong>Zen</strong> Page icon.<br />

5. Click OK. The <strong>Zen</strong> Page Wizard dialog displays.<br />

6. Enter data in the following fields:<br />

• Package Name — Package that will contain the new page class.<br />

• Class Name — Class name of the new page class.<br />

• Application — Package and class name of the application that this page belongs to.<br />

• Page Name — Logical name of this page within its application.<br />

• Domain — Domain this page will use for localization of caption text.<br />

<strong>Using</strong> <strong>Zen</strong> 447


<strong>Zen</strong> Wizards<br />

• Description — Any text that you want to use to describe the page.<br />

• Page type — Choose one of the following:<br />

- Page — Normal page class.<br />

- Subclass of Template Page — Subclass of a template page class. If you choose this option,<br />

the Super class combo box displays. If you click the down-arrow in this box, a list of<br />

page class names displays. The list is alphabetical by package name. Choose a page class<br />

from this listp;.<br />

7. Click Next.<br />

8. Choose an initial page layout:<br />

• Column 2 — Two columns, plus space for a title along the top<br />

• Title Page — Space for a title along the top<br />

• Default — No pre-defined layout<br />

9. Click Finish. The dialog closes and your new <strong>Zen</strong> page class displays in Studio.<br />

10. Modify the <strong>Zen</strong> page class as desired:<br />

• To supply style definitions for the page, use the <strong>Zen</strong> Style Wizard to edit XData Style.<br />

• To supply page contents, edit XData Contents. Within XData Contents you may add components<br />

using Studio Assist or the <strong>Zen</strong> Element Wizard. A wizard is also available for adding<br />

charts.<br />

• To add server-side and client-side methods, use the <strong>Zen</strong> Method Wizard.<br />

11.<br />

12.<br />

Choose Build > Compile or Ctrl-F7 or the icon.<br />

Choose View > Web Page or the icon. The page displays in the browser.<br />

22.4 New <strong>Zen</strong> Report Wizard<br />

Note:<br />

For background information and a sample wizard session, see <strong>Zen</strong> Reports.<br />

You can use the New <strong>Zen</strong> Report Wizard as follows:<br />

1. Start Studio.<br />

448 <strong>Using</strong> <strong>Zen</strong>


New <strong>Zen</strong> Report Wizard<br />

2.<br />

Choose File > New or Ctrl-N or the icon.<br />

3. Select the Custom tab.<br />

4. Click the New <strong>Zen</strong> Report icon.<br />

5. Click OK. The <strong>Zen</strong> Report Wizard dialog displays.<br />

6. Enter data in the following fields:<br />

• Package Name — Package that will contain the report class.<br />

• Class Name — Report class name.<br />

• Application — Package and class name of the application that this report belongs to.<br />

• Report Name — Logical name of this report within its application.<br />

• Description — Any text that you want to use to describe the report.<br />

7. Click Next. The wizard prompts for an SQL query to provide data for the report.<br />

8. Type an SQL query into the text box<br />

9. Click Finish. The dialog closes and your new <strong>Zen</strong> report class displays in Studio.<br />

10. Find the following text in the XData ReportDefinition block:<br />

<br />

Delete this comment. Add a element between and the closing element.<br />

Note:<br />

For background information, see the <strong>Zen</strong> Reports topic XData ReportDefinition.<br />

11. Find the following text in the XData ReportDisplay block.<br />

<br />

Delete this comment. Add a element between and the closing element.<br />

Note:<br />

For background information, see the <strong>Zen</strong> Reports topic XData ReportDisplay.<br />

12. Set the DEFAULTMODE class parameter value to indicate the report output format.<br />

13. Modify the <strong>Zen</strong> report class as desired.<br />

14.<br />

15.<br />

Choose Build > Compile or Ctrl-F7 or the icon.<br />

Choose View > Web Page or the icon. The report displays in the browser.<br />

<strong>Using</strong> <strong>Zen</strong> 449


<strong>Zen</strong> Wizards<br />

22.5 Studio Assist<br />

Note:<br />

The <strong>Zen</strong> Tutorial chapter explores Studio Assist in the topics Hello World and Creating a<br />

<strong>Zen</strong> Page.<br />

You can use Studio Assist (word completion as you type) within <strong>Zen</strong> classes as follows:<br />

1. Start Studio.<br />

2. Open a <strong>Zen</strong> page or report class.<br />

3. Position the cursor in one of the following elements:<br />

• XData Contents, between and <br />

• XData ReportDefinition, between and <br />

• XData ReportDisplay, between and <br />

4. Begin typing. At the first meaningful character, Studio provides a context-sensitive list of appropriate<br />

XML elements and attributes. This list includes the built-in <strong>Zen</strong> components as well as any<br />

custom or composite components that you have defined.<br />

5. To choose an item from this list, click on it and press Enter.<br />

6. Studio completes the word and adds it to the code.<br />

22.6 <strong>Zen</strong> Chart Wizard<br />

Note:<br />

For background information, see <strong>Zen</strong> Charts.<br />

Every chart is an SVG component as described in <strong>Zen</strong> and SVG. This means that charts follow the<br />

layout and style conventions for SVG components, with the additional characteristics described in <strong>Zen</strong><br />

Charts. Most importantly, a <strong>Zen</strong> chart must appear within an container. Remember this<br />

when adding a chart to XData Contents.<br />

You can use the <strong>Zen</strong> Chart Wizard as follows:<br />

1. Start Studio.<br />

2. Open the class.<br />

3. Position the cursor inside XData Contents.<br />

4. Press CTRL-T to display the list of <strong>Zen</strong> templates.<br />

450 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Chart Wizard<br />

5. Select the <strong>Zen</strong> Chart Wizard.<br />

6. Click OK. The <strong>Zen</strong> Chart Wizard dialog displays.<br />

7. The Type field presents a list of chart types.<br />

• barChart — See Bar Charts<br />

• diffChart — See Difference Charts<br />

• hilowChart — See High/Low Charts<br />

• lineChart — See Line Charts<br />

• pieChart — See Pie Charts<br />

• xyChart — See Scatter Diagrams<br />

8. Choose a chart type.<br />

9. Click Next. The <strong>Zen</strong> Chart Wizard displays a split screen:<br />

• At left is an illustration of how the current attributes affect chart style.<br />

• At right is a list of attributes. Above this list, you can click Chart, X Axis, or Y Axis to view<br />

the attributes for these different aspects of the chart.<br />

10.<br />

To provide a value for any attribute, click in the field beside it. A popup button displays in<br />

the field. Click on the popup button. The <strong>Zen</strong> Value Editor dialog pops up. The entry field in this<br />

dialog is sensitive to the data type of the property. For example:<br />

• If the type is boolean, the dialog provides a checkbox.<br />

• If one value must be selected from a set, the dialog displays radio buttons.<br />

• If the type is a CSS style definition, the CSS Declaration Editor pops up.<br />

• If the type is a JavaScript expression, a text area offers room to type the entry.<br />

In all cases, a brief description of the property appears on the dialog, below the entry field. For<br />

details, and for descriptions of how the individual properties work together, you can find documentation<br />

in the chapter <strong>Zen</strong> Charts.<br />

Click OK to save your changes and return to the <strong>Zen</strong> Chart Wizard. The list of chart attributes now<br />

contains your entry. You may repeat this step as often as needed to supply attributes for this chart.<br />

11. To accept the result of all your changes to this chart definition, click Finish. The <strong>Zen</strong> Chart Wizard<br />

dialog closes and the completed chart definition appears in the XData Contents block of your <strong>Zen</strong><br />

page class.<br />

<strong>Using</strong> <strong>Zen</strong> 451


<strong>Zen</strong> Wizards<br />

22.7 <strong>Zen</strong> Element Wizard<br />

Note:<br />

For background information, see <strong>Zen</strong> Layout.<br />

You can use the <strong>Zen</strong> Element Wizard as follows:<br />

1. Start Studio.<br />

2. Open the class.<br />

3. Position the cursor inside XData Contents.<br />

4. Press CTRL-T to display the list of <strong>Zen</strong> templates.<br />

5. Select the <strong>Zen</strong> Element Wizard.<br />

6. Click OK. The <strong>Zen</strong> Element Wizard dialog displays.<br />

7. In the Element field, click the down-arrow to display a dropdown list of <strong>Zen</strong> components. This<br />

list includes the built-in <strong>Zen</strong> components as well as any custom or composite components that<br />

you have defined. Components in this list are sorted alphabetically by package name, so the order<br />

is:<br />

• Auxiliary components, such as for <br />

• Built-in <strong>Zen</strong> components, such as <br />

• User-defined components, such as composites or custom components<br />

8. Click on a component name.<br />

9. Click Next. The <strong>Zen</strong> Element Wizard displays an alphabetical list of the properties of the component<br />

that you selected.<br />

10. To provide a value for any property, click the Edit button beside its name. The <strong>Zen</strong> Value Editor<br />

dialog pops up. The entry field in this dialog is sensitive to the data type of the property. For<br />

example:<br />

• If the type is boolean, the dialog provides a checkbox.<br />

• If one value must be selected from a set, the dialog displays radio buttons.<br />

• If the type is a CSS style definition, the CSS Declaration Editor pops up.<br />

• If the type is a JavaScript expression, a text area offers room to type the entry.<br />

In all cases, a brief description of the property appears on the dialog, below the entry field. For<br />

details, and for descriptions of how the individual properties work together, you can find documentation<br />

in this manual, particularly:<br />

452 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Method Wizard<br />

• <strong>Zen</strong> Layout<br />

• <strong>Zen</strong> Style<br />

• <strong>Zen</strong> Tables<br />

• <strong>Zen</strong> and SVG<br />

• <strong>Zen</strong> Charts<br />

• <strong>Zen</strong> Forms<br />

• <strong>Zen</strong> Controls<br />

• Model View Controller<br />

• <strong>Zen</strong> Navigation<br />

• Popup Windows and Dialogs<br />

• Other <strong>Zen</strong> Components<br />

• Custom Components<br />

Click OK to save your changes and return to the <strong>Zen</strong> Element Wizard. The list of properties now<br />

contains your entry. You may repeat this step as often as needed to supply values for properties<br />

of this component.<br />

11. To accept the result of all your changes to this component definition, click Finish. The <strong>Zen</strong> Element<br />

Wizard dialog closes and the completed component definition appears in the XData Contents<br />

block of your <strong>Zen</strong> page class.<br />

22.8 <strong>Zen</strong> Method Wizard<br />

Note:<br />

For background information, see <strong>Zen</strong> Application Programming. The <strong>Zen</strong> Tutorial chapter<br />

provides sample <strong>Zen</strong> Method Wizard sessions in the topics Step 3: Client-side Method and<br />

Step 5: Server-side Method.<br />

You can use the <strong>Zen</strong> Method Wizard as follows:<br />

1. Start Studio.<br />

2. Open a <strong>Zen</strong> page class.<br />

3. Position the cursor at the end of the class, but before the final closing brace }.<br />

4. Press CTRL-T to display the list of <strong>Zen</strong> templates.<br />

5. Select the <strong>Zen</strong> Method Wizard.<br />

<strong>Using</strong> <strong>Zen</strong> 453


<strong>Zen</strong> Wizards<br />

6. Click OK. The <strong>Zen</strong> Method Wizard dialog displays.<br />

7. Choose a method Scope, either instance or class.<br />

8. Choose a Location where the method will execute, and enter a Method Name.<br />

By convention, method execution and names are related as follows. See the chapter <strong>Zen</strong> Tutorial,<br />

topic <strong>Zen</strong> Naming Conventions for details:<br />

Location Choice<br />

runs on the client<br />

runs on the server<br />

is only available on the server<br />

is a server-side callback for a component<br />

Method Type<br />

Client-only<br />

<strong>Zen</strong> method<br />

Server-only utility<br />

Server-only callback<br />

Naming<br />

Convention<br />

myMethod<br />

MyMethod<br />

%MyMethod<br />

MyMethod<br />

9. If you choose the option is a server-side callback for a component in the previous step, the <strong>Zen</strong><br />

Method Wizard dialog adds a Server-side callback field. This field offers a dropdown list of<br />

attributes whose value is the name of a server-side callback method. These include attributes such<br />

as OnSubmitForm or OnDrawContent. Choose a component and attribute from<br />

this list.<br />

The Server-side callback entry adds a comment to your method body, reminding you which component<br />

and attribute you intend to associate with this callback method. You must still add the<br />

relevant attribute to the component definition in XData Contents, but the reminder can be useful<br />

as you work with the class.<br />

10. In the Description field, enter any text that you want to use to describe the method.<br />

11. Leave the Try/Catch box checked if you want the wizard to write a try/catch error processing<br />

template into your method. For details, see the <strong>Using</strong> Caché ObjectScript chapter, Error Processing.<br />

In a client-side method the template looks like this:<br />

Method mMethod() [Language = JavaScript]<br />

{<br />

try {<br />

alert('Client Method');<br />

// TODO: implement<br />

}<br />

catch (ex) {<br />

zenExceptionHandler(ex,arguments);<br />

}<br />

}<br />

In a server-side method the template looks like this<br />

454 <strong>Using</strong> <strong>Zen</strong>


<strong>Zen</strong> Style Wizard<br />

Method MyMethod() [<strong>Zen</strong>Method]<br />

{<br />

Try {<br />

// TODO: implement<br />

&js<br />

}<br />

Catch(ex) {<br />

&js<br />

}<br />

Quit<br />

}<br />

To skip this feature, uncheck the Try/Catch box.<br />

12. Click Finish. The dialog closes and your new method definition displays within the <strong>Zen</strong> page class<br />

in Studio.<br />

13. Implement the method as desired.<br />

22.9 <strong>Zen</strong> Style Wizard<br />

Note:<br />

For background information, see <strong>Zen</strong> Style.<br />

You can use the <strong>Zen</strong> Style Wizard as follows:<br />

1. Start Studio.<br />

2. Open the class whose XData Style block you want to edit.<br />

3. Within the XData Style block, position the cursor between and .<br />

4. Press CTRL-T to display the list of <strong>Zen</strong> templates.<br />

5. Select the <strong>Zen</strong> Style Wizard.<br />

6. Click OK. A list of pre-defined styles appears. This list is organized alphabetically by component<br />

name. As discussed in the chapter <strong>Zen</strong> Style, topic Overriding Built-in Styles, some of the component<br />

names may be unfamiliar. These are the parent classes for components that you actually place<br />

on the <strong>Zen</strong> page. For example, to edit styles for tablePane (the child) you must select styles from<br />

the list provided for simpleTablePane (the parent).<br />

7. Scroll down the list to see the styles that it offers.<br />

8. Select the radio button next to the name of the CSS style you want to edit.<br />

9. Click Next. The <strong>Zen</strong> Style Wizard echoes your selection and provides a sample of its current<br />

appearance.<br />

10. Click Edit. The CSS Declaration Editor displays. You can add, remove, or edit statements as many<br />

times as needed to define the CSS rule.<br />

<strong>Using</strong> <strong>Zen</strong> 455


<strong>Zen</strong> Wizards<br />

11. To add a CSS name-value pair:<br />

• Click on the item --New-- in the CSS Declarations text box.<br />

• Click the down-arrow on the Property box to display an alphabetized list of CSS argument<br />

names (background-color, font-weight, width, etc). Click on a name to choose it.<br />

• Either type a CSS value in the Value field or click the Edit button to display the CSS Value<br />

Editor.<br />

• The CSS Value Editor is sensitive to the values that can be entered for the CSS argument you<br />

chose. If there is a fixed list of options, you can choose them from a dropdown list. If there<br />

is the option of typing in a value other than the fixed list, you can do that too.<br />

• If you choose a compound CSS style argument such as border-top, the editor prompts you<br />

for each choice independently, for example:<br />

- width — thin, medium, thick, 1px, 2px, 3px, 4px, inherit<br />

- style — none, hidden, dotted, dashed, solid, double, groove, ridge, inset, outset, inherit<br />

- color — A dropdown list of standard CSS color names including black, blue, red, darkred,<br />

etc. Alternatively you can click the Browse button to display a detailed color choice<br />

dialog where you can make a visual color selection. When you click on a color sample<br />

in this dialog and click OK, <strong>Zen</strong> provides this color to your CSS statement as an HTML<br />

color value.<br />

The result is then something like this: border-top: 1px solid #70DFF0;<br />

• Click OK to save your changes and return to the CSS Declaration Editor. The CSS Declarations<br />

text box now contains the new name-value pair, as well as any others you have previously<br />

added.<br />

12. To remove a CSS name-value pair:<br />

• Click on the corresponding line in the CSS Declarations text box.<br />

• Click the Remove button to the right of the Property box.<br />

• Click OK to save your changes and return to the CSS Declaration Editor. The CSS Declarations<br />

text box no longer displays the name-value pair that you removed.<br />

13. To edit a CSS name-value pair:<br />

• Click on the corresponding line in the CSS Declarations text box.<br />

• Either type a CSS value in the Value field or click the Edit button to display the CSS Value<br />

Editor.<br />

• Use the CSS Value Editor to choose and enter values as in step 11.<br />

456 <strong>Using</strong> <strong>Zen</strong>


• Click OK to save your changes and return to the CSS Declaration Editor. The CSS Declarations<br />

text box now contains the modified version of the name-value pair, as well as any others you<br />

have previously added.<br />

14. When you are satisfied with your modifications in the CSS Declaration Editor dialog, click OK.<br />

The <strong>Zen</strong> Style Wizard echoes your choices and displays a sample of the resulting style. After<br />

examining this sample you may do one of the following:<br />

• To resume changes to this style definition, return to step 10.<br />

<strong>Zen</strong> Style Wizard<br />

• To accept the result of all your changes to this style definition, click Finish. The <strong>Zen</strong> Style<br />

Wizard dialog closes and the completed style definition appears in the XData Style block of<br />

your class.<br />

<strong>Using</strong> <strong>Zen</strong> 457


Index<br />

Symbols<br />

$$$Text, 396<br />

$$$TextHTML, 396<br />

$$$TextJS, 396<br />

$DATASOURCE, 439<br />

$LOG, 441<br />

$MODE, 438<br />

&html<br />

%Attr, 348<br />

%DrawHTML, 343<br />

OnDrawCell, 82<br />

OnDrawContent<br />

expando, 281<br />

html element, 47<br />

%application, 365<br />

%Attr, 348<br />

%composite, 365<br />

%DrawHTML, 28, 343<br />

%GetEventHandlers, 348<br />

%id, 252<br />

%MakeId, 346<br />

%OnGetSubtitle, 301<br />

%OnGetTitle, 301<br />

%OnSubmit, 164<br />

%page, 366<br />

%query, 365<br />

%seriesCount, 252<br />

%seriesNames, 252<br />

%session, 365<br />

%this, 366<br />

%url, 365<br />

%val, 414<br />

%zenContext, 367<br />

A<br />

action, 175<br />

aggregate, 415<br />

AJAX, 376<br />

align<br />

components, 57<br />

line, 432<br />

table, in reports, 434<br />

altcolor, 434<br />

animate, 113<br />

APPLICATION, 364<br />

APPLICATIONNAME, 362<br />

applications, 31<br />

programming, 361<br />

security, 391<br />

wizard, 445<br />

see also %application<br />

APPLYBUTTON, 302<br />

att, 425<br />

Attr<br />

see %Attr<br />

attribute, 415<br />

autoExecute, 92<br />

AUTOLOGOUT, 364<br />

autoRefresh, 225<br />

autoValidate, 158<br />

auxColumn, 198<br />

axes, 152<br />

B<br />

backgroundStyle<br />

charts, 146<br />

radialNavigator, 123<br />

svgFrame, 105<br />

backgroundTimerInterval, 379<br />

bandLower, 146<br />

bandLowerStyle, 146<br />

bandUpper, 146<br />

bandUpperStyle, 146<br />

barChart, 131<br />

baseValue, 152<br />

block, 429<br />

body, 427<br />

bodyHeight, 84<br />

breakOnExpression, 419<br />

breakOnField, 419<br />

browsers, 4<br />

button, 174<br />

buttonCaption, 193<br />

buttonImage, 193<br />

buttonImageDown, 193<br />

buttonTitle, 194<br />

<strong>Using</strong> <strong>Zen</strong> 459


C<br />

Caché Server Pages, 25<br />

calendar, 202<br />

caption<br />

button, 174<br />

checkbox, 179<br />

datatype, and localization, 400<br />

expando, 282<br />

links, 264<br />

locatorLink, 266<br />

menus, 269<br />

radialNode, 124<br />

radioButton, 184<br />

reports, 435<br />

submit, 175<br />

tab, 279<br />

tablePane, 84<br />

captionClass, 179<br />

radioButton, 184<br />

radioSet, 183<br />

case-sensitivity, 22<br />

cellAlign, 51<br />

cellSize, 51<br />

cellStyle<br />

condition, 85<br />

groups, 51<br />

cellTitle, 82<br />

cellVAlign, 52<br />

chartFilled, 130<br />

chartPivot<br />

barChart, 132<br />

hilowChart, 135<br />

lineChart, 130<br />

charts, 127<br />

axis attributes, 152<br />

barChart, 131<br />

common attributes, 145<br />

diffChart, 133<br />

hilowChart, 135<br />

lineChart, 129<br />

ongetData, 143<br />

pieChart, 138<br />

reports, 436<br />

wizard, 450<br />

xAxis, 152<br />

xyChart, 136<br />

yAxis, 152<br />

chartStacked<br />

barChart, 132<br />

lineChart, 130<br />

checkbox, 178<br />

childIndent<br />

dynaTree, 320<br />

expando, 282<br />

choiceColumn, 198<br />

class<br />

attribute<br />

for aggregate, 416<br />

in reports, 428<br />

element, in reports, 424<br />

clearSnapshot, 88<br />

client and server, 25<br />

clientType, 170<br />

code examples, 23<br />

colExpression, 82<br />

colName<br />

column, 82<br />

condition, 85<br />

color, 432<br />

color definitions, 337<br />

colorList, 180<br />

colorPane, 311<br />

colorPicker, 180<br />

colorSelect, 300<br />

cols, 177<br />

column, 81<br />

columnHeaders, 199<br />

columnName, 214<br />

combobox, 191<br />

comboType, 194<br />

components<br />

common attributes, 57<br />

concepts, 37<br />

layout, 43<br />

security, 392<br />

wizard, 446<br />

see also SVG components<br />

composite, 328<br />

see also %composite<br />

condition, 57, 85<br />

containerStyle, 58<br />

CONTAINS, 86<br />

content, 306<br />

controlClass, 170<br />

controller<br />

see Model View Controller<br />

460 <strong>Using</strong> <strong>Zen</strong>


controllerId<br />

charts, 144<br />

data views, 226<br />

dynaGrid, 215<br />

forms, 159, 166<br />

meters, 113<br />

controls, 155<br />

button, 174<br />

calendar, 202<br />

checkbox, 178<br />

colorPicker, 180<br />

combobox, 191<br />

common attributes, 169<br />

dataCombo, 195<br />

dataListBox, 189<br />

dateText, 205<br />

dynaForm, 243<br />

dynaGrid, 207<br />

fileUpload, 179<br />

hidden, 207<br />

image, 174<br />

label, 176<br />

listBox, 188<br />

password, 177<br />

radioButton, 183<br />

radioSet, 180<br />

select, 185<br />

submit, 175<br />

text, 176<br />

textarea, 177<br />

controlStyle, 170<br />

count, 433<br />

createComponent, 288<br />

CSP, 25<br />

CSS<br />

cascade of styles, 63<br />

custom components, 334<br />

overriding styles, 65<br />

style wizard, 455<br />

cssinclude, 425<br />

CSSINCLUDES<br />

application class, 362<br />

page class, 364<br />

currCol, 312<br />

currColumn<br />

dynaGrid, 215<br />

tablePane, 97<br />

currPage<br />

dynaGrid, 215<br />

tablePane, 88<br />

currRow<br />

colorPane, 312<br />

dynaGrid, 215<br />

currSlice, 312<br />

currTab, 275<br />

D<br />

dashboards, 101<br />

dataBinding<br />

controls, 170<br />

data views, 226<br />

meters, 113<br />

dataCombo, 195<br />

dataController, 222<br />

dataFields, 436<br />

dataGlobal, 320<br />

dataGroup, 436<br />

dataListBox, 189<br />

dataSource, 73<br />

DATASOURCE, 411<br />

see also $DATASOURCE<br />

dateText, 205<br />

dayList, 203<br />

defaultGroupId, 166<br />

DEFAULTMODE, 411<br />

defaultSeries, 223<br />

defs, 336<br />

delay, 194<br />

demo applications, 7<br />

dialog windows, 299<br />

dictionary, message, 396<br />

diffChart, 133<br />

disabled<br />

controls, 170<br />

groups, 52<br />

links, 264<br />

menus, 269<br />

svgFrame, 105<br />

svgGroup, 109<br />

displayColumns, 199<br />

displayList<br />

combobox, 192<br />

radioSet, 181<br />

select, 186<br />

document, 424<br />

DOMAIN<br />

and dialogs, 302<br />

<strong>Using</strong> <strong>Zen</strong> 461


and localization, 400<br />

page class parameter, 364<br />

dragCanvas, 105<br />

DrawHTML<br />

see %DrawHTML<br />

dropdownHeight, 194<br />

dropdownWidth, 194<br />

dynaForm, 166<br />

control labels, 241<br />

control selection, 243<br />

dynaGrid, 207<br />

DYNAMICPROPERTIES, 253<br />

dynaTree, 316<br />

dynaView, 322<br />

E<br />

editable, 194<br />

editMode, 105<br />

element<br />

in reports, 414<br />

on pages<br />

layout, 43<br />

wizard, 452<br />

emptyCaption, 183<br />

enclosingClass, 58<br />

enctype, 159<br />

endYear, 203<br />

EQ, 86<br />

escape, 298<br />

events<br />

%GetEventHandlers, 348<br />

charts<br />

get chart labels, 147<br />

update chart, 143<br />

user clicks, 151<br />

colorPane, 313<br />

controls, 171<br />

dataController, 224<br />

dynaGrid, 216<br />

dynaTree, 321<br />

dynaView, 324<br />

eventHandler, 341<br />

expando, 283<br />

forms, 159<br />

link, 264<br />

lookoutMenu, 278<br />

menus<br />

submenus, 271<br />

user clicks, 270<br />

meters, 114<br />

modalGroup, 297<br />

ownerDraw, 125<br />

radialNavigator, 123<br />

radialNode, 124<br />

SVG components, 110<br />

svgFrame, 106<br />

tablePane<br />

row and column selection, 96<br />

user key clicks, 95<br />

tabs, 275<br />

timer, 309<br />

zenEvent, 367<br />

examples, 23<br />

expandable, 277<br />

expanded<br />

expando, 282<br />

lookoutMenu, 278<br />

expando, 279<br />

expression, 415<br />

runtime, 368<br />

EXTEQ, 86<br />

extraColumnWidth, 84<br />

F<br />

face, 312<br />

field attribute<br />

for element, 415<br />

for item, 431<br />

fieldSet, 309<br />

fileSelect, 300<br />

fileUpload, 179<br />

filterEnum, 90<br />

filterEnumDisplay, 90<br />

filterLabel, 90<br />

filterOp, 91<br />

filterQuery, 91<br />

filtersDisabled, 92<br />

filterTitle, 91<br />

filterType, 91<br />

filterValue, 91<br />

findElement, 347<br />

findSVGElement, 347<br />

firstDayOfWeek, 203<br />

fixedHeaders, 84<br />

462 <strong>Using</strong> <strong>Zen</strong>


fixedMonth, 203<br />

fo, 437<br />

footer, 430<br />

footerHeight<br />

document, 424<br />

formatNumber, 431<br />

forms, 155<br />

common attributes, 158<br />

controls, 169<br />

dynamic, 166<br />

Model View Controller, 228<br />

submit, 164<br />

validation, 162<br />

frameAlign, 307<br />

frameBorder, 307<br />

frameStyle, 105<br />

fuelGauge, 115<br />

G<br />

gapWidth, 203<br />

getComponentById, 286<br />

getDialogValue, 301<br />

GetEventHandlers<br />

see %GetEventHandlers<br />

getRowData, 88<br />

graphics<br />

dynamic, using SVG, 101<br />

static images<br />

clickable, 174<br />

display-only, 307<br />

gridLabel, 215<br />

gridStyle, 147<br />

gridX, 105<br />

gridY, 106<br />

groupByClause, 74<br />

groupClass, 52<br />

groups<br />

in reports<br />

list, 433<br />

table, 434<br />

XData ReportDefinition, 418<br />

XData ReportDisplay, 429<br />

on pages<br />

common attributes, 50<br />

dialog windows, 299<br />

dynaForm, 166<br />

expando, 279<br />

fieldSet, 309<br />

form, 158<br />

forms, 155<br />

hgroup, 48<br />

layout, 48<br />

menus, 267<br />

modal groups, 285<br />

page, 45<br />

pane, 54<br />

repeatingGroup, 313<br />

svgGroup, 109<br />

tabs, 271<br />

vgroup, 49<br />

groupStyle, 52<br />

groupTitle, 297<br />

GT, 86<br />

GTEQ, 87<br />

H<br />

header, 82, 430<br />

headerHeight<br />

document, 424<br />

headerLayout, 93<br />

height<br />

components, 58<br />

document, 424<br />

gridRow, 212<br />

img, 431<br />

SVG components, 110<br />

help<br />

menus, 269<br />

hgroup, 48<br />

see also groups<br />

hidden, 207<br />

column, 82<br />

components, 58<br />

gridColumn, 214<br />

gridRow, 212<br />

SVG components, 110<br />

highLampColor<br />

fuelGauge, 116<br />

lightBar, 118<br />

speedometer, 120<br />

<strong>Using</strong> <strong>Zen</strong> 463


highStyle, 117<br />

hilowChart, 135<br />

hmenu, 270<br />

HOMEPAGE, 362<br />

horizontal, 48<br />

href<br />

cssinclude, 426<br />

link, 264<br />

locatorLink, 266<br />

xslinclude, 426<br />

HTML, 3<br />

see also &html<br />

html element<br />

for page titles, 47<br />

for static HTML content, 305<br />

in reports, 438<br />

HTMLSTYLESHEET, 412<br />

hubStyle, 123<br />

I<br />

id<br />

components, 58<br />

locatorLink, 266<br />

modelId, 224<br />

SVG components, 111<br />

see also %id<br />

iframe, 307<br />

image<br />

attribute, for list, 433<br />

element, on pages, 174<br />

menus, 269<br />

imageContracted<br />

dynaTree, 320<br />

expando, 282<br />

imageExpanded<br />

dynaTree, 320<br />

expando, 282<br />

imageHeight, 269<br />

imageWidth, 269<br />

img, 430<br />

import, 58<br />

independentOdometer, 120<br />

indicatorLamp, 116<br />

initialExecute, 73<br />

invalid, 171<br />

invalidDateMessage, 206<br />

invalidMessage<br />

controls, 171<br />

forms, 159<br />

item, 431<br />

itemCount, 191<br />

J<br />

JavaScript, 14, 375<br />

JSINCLUDES<br />

application class, 362<br />

page class, 364<br />

K<br />

key, 159<br />

L<br />

label<br />

components, 59<br />

dynaForm, 241<br />

element, in forms, 176<br />

gridColumn, 214<br />

gridRow, 212<br />

meter components, 113<br />

labelAngle, 152<br />

labelClass, 59<br />

labelPosition, 52<br />

labelStyle<br />

axes, 152<br />

charts, 147<br />

components, 59<br />

meter components, 114<br />

labelsVisible, 147<br />

labelUnits, 152<br />

labelValues, 437<br />

language, application locale and, 395<br />

lastUpdate, 99<br />

layout<br />

components, 43<br />

groups, 52<br />

svgFrame, 106<br />

svgGroup, 109<br />

table, in reports, 435<br />

see also style<br />

legend, 311<br />

legendHeight, 149<br />

legendLabelStyle, 150<br />

legendStyle, 150<br />

legendVisible, 150<br />

legendWidth, 150<br />

464 <strong>Using</strong> <strong>Zen</strong>


legendX, 150<br />

legendY, 150<br />

length, 433<br />

lightBar, 118<br />

line<br />

between groups, 429<br />

for line breaks, 432<br />

lineChart, 129<br />

lineHeight, 433<br />

link<br />

column, 93<br />

element, in navigation, 263<br />

item, 432<br />

menus, 269<br />

linkCaption, 93<br />

linkConfirm, 94<br />

linkResource, 270<br />

list, 433<br />

listBox, 188<br />

common attributes, 189<br />

listHeight, 189<br />

listWidth, 189<br />

loadingMessage, 199<br />

localization, 395<br />

locatorBar, 265<br />

locatorLink, 266<br />

LOG<br />

see $LOG<br />

logo<br />

fuelGauge, 116<br />

speedometer, 120<br />

longdesc, 307<br />

lookoutMenu, 275<br />

lowLampColor<br />

fuelGauge, 116<br />

lightBar, 118<br />

speedometer, 120<br />

lowStyle, 117<br />

LT, 87<br />

LTEQ, 87<br />

M<br />

mainLabel, 123<br />

mainLabelStyle, 123<br />

majorGridLines, 153<br />

majorGridStyle, 153<br />

majorUnits, 153<br />

makeId, 346<br />

see also %MakeId<br />

marginBottom<br />

charts, 146<br />

document, 424<br />

marginLeft<br />

charts, 146<br />

document, 424<br />

marginRight<br />

charts, 146<br />

document, 424<br />

marginTop<br />

charts, 146<br />

document, 424<br />

markerScale, 149<br />

markerShapes, 149<br />

markerStyle, 149<br />

markersVisible, 149<br />

maxDate<br />

calendar, 203<br />

dateText, 206<br />

maxlength<br />

combobox, 194<br />

fileUpload, 179<br />

password, 177<br />

text, 176<br />

maxRows<br />

radioSet, 182<br />

select, 187<br />

tables, 74<br />

maxValue, 153<br />

menu, 267<br />

menuItem, 268<br />

menuSeparator, 271<br />

message dictionary, 396<br />

meters, 112<br />

common attributes, 113<br />

custom, 353<br />

fuelGauge, 115<br />

indicatorLamp, 116<br />

lightBar, 118<br />

smiley, 119<br />

speedometer, 119<br />

trafficLight, 121<br />

method<br />

aggregate, 416<br />

conventions, 375<br />

wizard, 453<br />

<strong>Using</strong> <strong>Zen</strong> 465


minDate<br />

calendar, 204<br />

dateText, 206<br />

minorGridLines, 153<br />

minorGridStyle, 153<br />

minorUnits, 153<br />

minValue, 153<br />

modalGroup, 285<br />

MODE<br />

see $MODE<br />

modelClass, 223<br />

modelId, 224<br />

Model View Controller, 219<br />

month, 204<br />

monthList, 204<br />

multiColumn, 199<br />

multiSelect, 97<br />

MVC, 219<br />

N<br />

name<br />

att, 425<br />

components, 59<br />

CSS style class, in reports, 425<br />

element, 415<br />

group<br />

XData ReportDefinition, 419<br />

XData ReportDisplay, 430<br />

locatorLink, 266<br />

report, 423<br />

SVG components, 111<br />

naming conventions, 22<br />

navigation<br />

tables, 89, 95<br />

NEQ, 87<br />

nextPage<br />

forms, 159<br />

submit, 176<br />

nodeStyle, 123<br />

normalStyle, 117<br />

nowrap, 84<br />

O<br />

odometerValue, 120<br />

offsetX, 106<br />

offsetY, 106<br />

okCaption, 297<br />

onaction, 297<br />

onactivate, 271<br />

onblur, 171<br />

onchange<br />

colorPane, 313<br />

controls, 171<br />

dynaTree, 321<br />

dynaView, 324<br />

forms, 159<br />

onchangecell, 216<br />

onclick<br />

controls, 171<br />

dynaTree, 321<br />

dynaView, 324<br />

link, 264<br />

menus, 270<br />

radialNode, 124<br />

SVG components, 110<br />

onclickcolumn, 216<br />

onclickrow, 216<br />

oncontract<br />

expando, 283<br />

lookoutMenu, 278<br />

oncreate, 224<br />

OnCreateResultSet<br />

group, in reports, 420<br />

tablePane, 77<br />

ondblclick<br />

colorPane, 313<br />

controls, 171<br />

dynaTree, 321<br />

dynaView, 324<br />

tablePane, 97<br />

ondefault, 160<br />

ondelete, 224<br />

ondragCanvas, 106<br />

ondrawcell, 216<br />

OnDrawCell, 82<br />

OnDrawContent<br />

expando, 283<br />

html, 307<br />

OnDrawFilter, 91<br />

OnDrawItem, 191<br />

oneditcell, 216<br />

onelementClick, 151<br />

onerror, 224<br />

OnExecuteResultSet, 77<br />

onexpand<br />

expando, 283<br />

466 <strong>Using</strong> <strong>Zen</strong>


lookoutMenu, 278<br />

onfocus, 171<br />

ongetData, 143<br />

ongetLabelX, 147<br />

ongetLabelY, 147<br />

OnGetNodeInfo, 321<br />

OnGetPropertyInfo, 166<br />

OnGetQuickLinks, 266<br />

OnGetSubtitle<br />

see %OnGetSubtitle<br />

OnGetTitle<br />

see %OnGetTitle<br />

OnGetViewContents, 324<br />

onheaderClick, 97<br />

onhideGroup, 297<br />

onhideTab, 275<br />

oninvalid, 160<br />

onkeydown, 172<br />

onkeypress<br />

controls, 172<br />

tablePane, 95<br />

onkeyup, 172<br />

OnLoadForm, 160<br />

onmousedown, 172<br />

onmouseout, 172<br />

onmouseover, 172<br />

onmouseup, 172<br />

onmouseWheel, 106<br />

onmoveItem, 106<br />

onmultiselect, 97<br />

onnotifyController, 224<br />

onnotifyView<br />

charts, 144<br />

data views, 226<br />

dynaGrid, 217<br />

forms, 160, 167<br />

meters, 114<br />

onPopupAction, 299<br />

onrender, 125<br />

onrenderPlotArea, 148<br />

onreset, 160<br />

onresizeItem, 107<br />

onsave, 224<br />

onselectItem, 107<br />

onselectNode, 123<br />

onselectrow, 97<br />

onshowGroup, 297<br />

onshowHelp, 271<br />

onshowTab, 275<br />

onsubmit<br />

controls, 172<br />

forms, 161<br />

see also %OnSubmit<br />

OnSubmitForm, 160<br />

ontimeout, 309<br />

onvalidate<br />

controls, 172<br />

forms, 161<br />

onzoom, 107<br />

option<br />

combobox, 192<br />

listBox, 188<br />

optionValue, 184<br />

orderByClause, 75<br />

orient, 435<br />

originalValue, 172<br />

ownerDraw, 125<br />

P<br />

p, 434<br />

page, 31<br />

element, 45<br />

programming, 363<br />

security, 392<br />

template page, 53<br />

wizard, 447<br />

see also %page<br />

pagebreak<br />

attribute, for group, 430<br />

element, in reports, 434<br />

pagefooter, 427<br />

pageheader, 427<br />

PAGENAME, 364<br />

pageSize, 88<br />

PAGETITLE, 364<br />

pane, 54<br />

dialog window, 301<br />

see also groups<br />

panel<br />

see fieldSet<br />

paneName, 54<br />

parameters<br />

dynaTree, 318<br />

dynaView, 322<br />

queries, 80<br />

SVG page references, 108<br />

<strong>Zen</strong> application class, 362<br />

<strong>Using</strong> <strong>Zen</strong> 467


<strong>Zen</strong> component class, 329<br />

<strong>Zen</strong> datatype, 338<br />

<strong>Zen</strong> page class, 363<br />

<strong>Zen</strong> page URI, 373<br />

<strong>Zen</strong> report class, 410<br />

paramName<br />

dynaTree, 318<br />

dynaView, 323<br />

password, 177<br />

pattern, 433<br />

PDF<br />

as report output, 403<br />

configuring <strong>Zen</strong> for PDF output, 440<br />

pieChart, 138<br />

pieScale, 138<br />

plotAreaStyle, 148<br />

plotBy, 138<br />

plotStyle, 148<br />

plotToEdge, 148<br />

popup windows<br />

dialogs, 299<br />

modal groups, 285<br />

predicate, 86<br />

preserveAspectRatio, 111<br />

preserve mode, exceptions to, 27<br />

Q<br />

query<br />

dataCombo, 196<br />

list box<br />

dataListBox, 190<br />

select, 187<br />

property parameters for, 254<br />

radioSet, 182<br />

repeatingGroup, 314<br />

report, 420<br />

to define a table, 73<br />

see also %query<br />

queryClass<br />

group, in reports, 420<br />

radioSet, 182<br />

select, 187<br />

tables, 76<br />

queryName<br />

group, in reports, 420<br />

radioSet, 182<br />

select, 187<br />

tables, 76<br />

R<br />

radialNavigator, 122<br />

radialNode, 122<br />

radioButton, 183<br />

radioSet, 180<br />

rangeLower, 114<br />

rangeUpper, 114<br />

readOnly<br />

controls, 172<br />

gridColumn, 214<br />

gridRow, 213<br />

readOnlyMessage, 161<br />

READONLYMODEL, 253<br />

rect, 109<br />

refLineStyle, 134<br />

remember<br />

expando, 283<br />

tab groups, 275<br />

repeatingGroup, 313<br />

see also tables<br />

REPORTNAME, 412<br />

reports, 403<br />

common attributes, 428<br />

wizard, 448<br />

XData ReportDefinition, 413<br />

XData ReportDisplay, 421<br />

REPORTXMLNAMESPACE, 412<br />

required, 173<br />

requiredMessage, 173<br />

RESOURCE, 364<br />

rowCount, 99<br />

rowLabelWidth, 217<br />

rowName, 213<br />

rows<br />

dynaView, 324<br />

textarea, 177<br />

rowSelect, 97<br />

rowStyle, 86<br />

runtime expression, 368<br />

runtimeMode, 420<br />

rx, 110<br />

S<br />

SAMPLES, 23<br />

scaleFactor, 114<br />

scrolling, 307<br />

scrollIntoView, 194<br />

468 <strong>Using</strong> <strong>Zen</strong>


searchKeyLen, 199<br />

security<br />

<strong>Zen</strong> application, 391<br />

<strong>Zen</strong> component, 392<br />

<strong>Zen</strong> page, 392<br />

seed<br />

column, 82<br />

html, 307<br />

modalGroup, 297<br />

select, 185<br />

selectedIndex<br />

combobox, 195<br />

dynaTree, 321<br />

dynaView, 324<br />

listBox, 189<br />

radialNavigator, 123<br />

tablePane, 97<br />

selectedItem, 151<br />

selectedItemStyle, 151<br />

selectedRows, 98<br />

selectedSeries, 151<br />

seriesColors<br />

charts, 148<br />

reports, 436<br />

seriesCount<br />

charts, 142<br />

reports, 436<br />

see also %seriesCount<br />

seriesGroup, 437<br />

seriesNames<br />

charts, 148<br />

reports, 437<br />

see also %seriesNames<br />

seriesSize<br />

charts, 142<br />

reports, 437<br />

server and client, 25<br />

session<br />

see also %session<br />

show, 295<br />

showColumnLabels, 217<br />

showEmpty<br />

dataCombo, 199<br />

select, 186<br />

showFilters, 93<br />

showPercentage, 138<br />

showQuery, 77<br />

showRowLabels, 217<br />

showRowNumbers, 84<br />

showRowSelector, 98<br />

showTabBar, 275<br />

showTime<br />

calendar, 204<br />

dateText, 206<br />

showValueInTooltip, 84<br />

showZebra, 85<br />

size<br />

combobox, 195<br />

dateText, 207<br />

fileUpload, 179<br />

password, 177<br />

select, 187<br />

text, 176<br />

slice, 59<br />

smiley, 119<br />

snapshot mode, for tables, 87<br />

snapToGrid, 107<br />

sortOrder, 96<br />

spacer, 49<br />

special, 432<br />

speedometer, 119<br />

sql<br />

group, in reports, 420<br />

radioSet, 182<br />

select, 187<br />

tables, 74<br />

sqlLookup<br />

dataCombo, 200<br />

dataListBox, 191<br />

src<br />

iframe, 308<br />

image, 175<br />

img, 431<br />

srcDisabled, 175<br />

STARTSWITH, 87<br />

startvalue, 433<br />

startYear, 204, 205<br />

streamId, 175<br />

Studio, 7<br />

<strong>Using</strong> <strong>Zen</strong> 469


style<br />

attribute<br />

column, 83<br />

gridColumn, 214<br />

gridRow, 213<br />

in reports, 423, 428<br />

link, 264<br />

option element, in combobox, 193<br />

option element, in listBox, 189<br />

radialNode, 124<br />

rect, 110<br />

components, 57<br />

element<br />

XData Style, 66, 334<br />

XData SVGStyle, 336<br />

inheritance, 62<br />

wizard, 455<br />

see also layout<br />

submit, 175<br />

see also %OnSubmit<br />

subtitle<br />

dialog windows, 301<br />

titleBox, 46<br />

summary, 435<br />

svgAutoSize, 107<br />

SVG components, 101<br />

common attributes, 110<br />

custom style, 336<br />

svgFrame, 102<br />

svgGroup, 109<br />

svgHeight, 107<br />

svgPage, 108<br />

svgSpacer, 109<br />

svgWidth, 108<br />

T<br />

tab, 278<br />

tabGroup, 272<br />

tableName, 75<br />

tableNavigator, 95<br />

tableNavigatorBar, 95<br />

tablePaneId, 95<br />

tables<br />

in reports, 434<br />

on pages, 72<br />

see also repeatingGroup<br />

tabResource, 279<br />

targetCol, 86<br />

template page, 53<br />

text<br />

element, 176<br />

language localization, 395<br />

listBox, 189<br />

option element<br />

combobox, 193<br />

listBox, 189<br />

see also $$$Text<br />

see also $$$TextHTML<br />

see also $$$TextJS<br />

textarea, 177<br />

thickness, 433<br />

this, 366<br />

see also %this<br />

thresholdLower, 114<br />

thresholdUpper, 114<br />

timeCaption, 205<br />

timeout, 309<br />

timer, 308<br />

title<br />

axes, 153<br />

charts, 150<br />

column, 83<br />

components, 59<br />

dialog windows, 301<br />

fieldSet, 311<br />

gridColumn, 214<br />

gridRow, 213<br />

links, 265<br />

locatorLink, 266<br />

page, 45<br />

radialNavigator, 124<br />

report, 423<br />

titleBox, 46<br />

titleBox, 46<br />

titleList, 183<br />

titlePane, 46<br />

titleStyle<br />

charts, 150<br />

radialNavigator, 124<br />

titleBox, 46<br />

titleX, 150<br />

titleY, 150<br />

trafficLight, 121<br />

translation, 395<br />

type<br />

aggregate, 416<br />

list, 433<br />

470 <strong>Using</strong> <strong>Zen</strong>


U<br />

style, 334<br />

style element, 66<br />

unrestricted, 195<br />

url<br />

see %url<br />

useKeys, 96<br />

USERPACKAGES, 364<br />

application class, 362<br />

USERSVGPACKAGES, 364<br />

application class, 362<br />

useSnapshot, 88<br />

V<br />

val<br />

see %val<br />

valign, 59<br />

value<br />

att, 425<br />

colorPane, 313<br />

condition, 86<br />

controls, 173<br />

dialog windows<br />

retrieving, 299<br />

returning, 301<br />

item, 432<br />

meters, 115<br />

modal groups, 290<br />

option element<br />

combobox, 193<br />

listBox, 189<br />

parameter element<br />

dynaTree, 318<br />

dynaView, 323<br />

SVG page references, 108<br />

table queries, 80<br />

radialNode, 124<br />

tablePane, 98<br />

valueColumn<br />

dataCombo, 200<br />

tablePane, 98<br />

valueList<br />

combobox, 192<br />

radioSet, 181<br />

select, 186<br />

vertical, 48<br />

vgroup, 49<br />

see also groups<br />

view<br />

see Model View Controller<br />

viewBoxHeight, 111<br />

viewBoxWidth, 111<br />

viewType, 324<br />

vmenu, 270<br />

W<br />

whereClause, 75<br />

width<br />

attribute, in reports, 428<br />

column, 83<br />

components, 59<br />

document, 424<br />

gridColumn, 214<br />

img, 431<br />

SVG components, 111<br />

wizards, 7, 445<br />

write, 438<br />

WRITE<br />

%Attr, 348<br />

%DrawHTML, 343<br />

OnDrawCell, 82<br />

OnDrawContent<br />

expando, 281<br />

html element, 47<br />

X<br />

x, 111<br />

xAxis, 152<br />

XData Contents, 44<br />

XData dialogBody, 301<br />

XData for panes, 54<br />

XData ReportDefinition, 413<br />

XData ReportDisplay, 421<br />

XData Style, 61<br />

XData SVGDef, 336<br />

XData SVGStyle, 336<br />

XHTML, 403<br />

XMLNamespace, 12<br />

xmlns, 45<br />

XSL-FO, 403<br />

XSLFOSTYLESHEET, 412<br />

xslinclude, 426<br />

XSLT, 403<br />

<strong>Using</strong> <strong>Zen</strong> 471


xyChart, 136<br />

Y<br />

y, 111<br />

yAxis, 152<br />

Z<br />

ZENATTRS, 253<br />

zenContext<br />

see %zenContext<br />

ZENCONTROL, 253<br />

ZENDISPLAYCOLUMN, 253<br />

ZENENCRYPT, 338<br />

zenEvent, 367<br />

ZENEXPRESSION, 339<br />

ZENGROUP, 254<br />

ZENHIDDEN, 254<br />

ZENLABEL<br />

and data models, 241<br />

datatype parameter, 254<br />

zenLaunchPopupWindow<br />

colorSelect, 301<br />

fileSelect, 300<br />

popup windows, 298<br />

utility function, 373<br />

zenLink<br />

popup windows, 298<br />

utility function, 373<br />

ZENLOCALIZE<br />

and localization, 400<br />

datatype parameter, 339<br />

<strong>Zen</strong>Method, 375<br />

zenPage, 366<br />

ZENREADONLY, 254<br />

ZENSETTING, 339<br />

ZENSIZE, 254<br />

ZENSQL, 254<br />

ZENSQLLOOKUP, 254<br />

zenSynchronousMode, 373<br />

ZENTAB, 254<br />

zenThis, 366<br />

ZENTITLE, 254<br />

ZENURL, 373<br />

zoom, 108<br />

zoomLevels, 108<br />

zoomWithWheel, 108<br />

472 <strong>Using</strong> <strong>Zen</strong>

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!