A Caché of Tips - Zen Custom Components

14 views
Skip to first unread message

Emily Haggstrom

unread,
Jan 23, 2012, 7:13:30 PM1/23/12
to intersy...@googlegroups.com

Today’s tip will cover some useful techniques as you develop more full-scale Zen applications. Zen allows you to create custom components and composites to capture some of your own commonly used features.

 

For instance, let’s say you have a tablePane on one of your pages:

 

<tablePane id="table" 
            caption="This is a tablePane"
            tableName="ZENDemo_Data.Employee"
            useSnapshot="true"
            showQuery="true"
            showFilters="true"
            fixedHeaders="true"
            bodyHeight="15.0em"

            filtersDisabled="false"
            autoExecute="true"
            showZebra="true"
            pageSize="10"
            showRowNumbers="true"
            valueColumn="ID"
            maxRows="1000"
            useKeys="true">
<column colName="ID" hidden="true"/>
.

.

.

<column colName="Salary" width="20%"/>
</tablePane>

 

You will probably use these same attribute definitions on many of your pages. To save on development time and add consistency to your application you can create a reusable component with these attributes. The <tablePane> component is an instance of %ZEN.Component.tablePane, and all of the attributes are properties of the class. You would start by subclassing the library class, then add an initial value for any properties you want to set. Dawn Wolthuis sent out a great example of this a couple of weeks ago, if you’d like to see an example “from the field”.

 

Class MyZEN.tablePane Extends %ZEN.Component.tablePane
{
Property useSnapshot As %ZEN.Datatype.boolean [ InitialExpression = ];
Property showQuery As %ZEN.Datatype.boolean [ InitialExpression = ];
Property showFilters As %ZEN.Datatype.boolean [ InitialExpression = ];
Property fixedHeaders As %ZEN.Datatype.boolean [ InitialExpression = ];
Property bodyHeight As %ZEN.Datatype.length [ InitialExpression = "15.0em" ];
Property filtersDisabled As %ZEN.Datatype.boolean [ InitialExpression = ];
Property autoExecute As %ZEN.Datatype.boolean [ InitialExpression = ];
Property showZebra As %ZEN.Datatype.boolean [ InitialExpression = ];
Property pageSize As %ZEN.Datatype.integer [ InitialExpression = "10" ];
Property showRowNumbers As %ZEN.Datatype.boolean [ InitialExpression = ];
Property valueColumn As %ZEN.Datatype.string [ InitialExpression = "ID" ];
Property maxRows As %ZEN.Datatype.integer [ InitialExpression = "1000" ];
Property useKeys As %ZEN.Datatype.boolean [ InitialExpression = ];

}

 

*NOTE: Use 1 and 0 instead of “true” and “false”. Client-side code expects string booleans, server-side code expects numeric booleans.

 

To reference this on a page, you need to define an xml namespace to identify your components by. This is usually a URL associated with your application to ensure that you don’t use the same namespace as someone else, but it’s really just a string. Add your namespace to the NAMESPACE parameter of the custom component class. You can use the same namespace for all of your components.

 

Parameter NAMESPACE = "www.myApplication.com";

 

You need to define a tag for components from your namespace to differentiate them from the default components. You can add your namespace declaration to the page tag to do so.

 

Class MyApp.CustomTableTest Extends %ZEN.Component.page
{
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]
{
<page xmlns="http://www.intersystems.com/zenxmlns:myzen="www.myApplication.com">
<myzen:tablePane tableName="Sample.Person">
<column colName="%ID"/>
<column colName="Name"/>
<column colName="FavoriteColors"/>
</myzen:tablePane>
</page>
}
}

 

Note that you still need to include the column definitions. Those are additional components.

 

If there is a whole set of components you reuse frequently, you can define a composite component. Let’s say the whole table from the previous example shows up on a bunch of your pages. You can save it as a custom component like this:

 

Class MyZEN.personTable Extends %ZEN.Component.composite
{
Parameter NAMESPACE = "www.myApplication.com";

XData Contents [XMLNamespace="http://www.intersystems.com/zen"]
{
<composite xmlns:myzen="www.myApplication.com">
<myzen:tablePane tableName="Sample.Person">
<column colName="%ID"/>
<column colName="Name"/>
<column colName="FavoriteColors"/>
</myzen:tablePane>
</composite>
}
}

 

A composite has an XData Contents section, just like a Zen page, but there’s no <page> component. Note that you’ll have to add your namespace to the <composite> tag if you’re using any custom components in the composite.

 

Using the composite component my page now looks like this:

 

Class MyApp.CustomTableTest Extends %ZEN.Component.page
{
XData Contents [XMLNamespace="http://www.intersystems.com/zen"]
{
<page xmlns="http://www.intersystems.com/zenxmlns:myzen="www.myApplication.com">
<myzen:personTable/>
</page>
}
}

 

Custom components and composites can also be used to help define a consistent look and feel for your application. You can add an XData Style block to either class. A good starting point is to find the style tags from the parent classes and copy them into your custom class. Then you can override the defaults with whatever you desire. Changes will automatically be applied to any classes that use your component.

 

For further reading and even more examples, check out this chapter in the documentation. Enjoy!

http://docs.intersystems.com/cache20111/csp/docbook/DocBook.UI.Page.cls?KEY=GZAP_customization

Benjamin Spead

unread,
Jan 24, 2012, 9:19:21 AM1/24/12
to intersy...@googlegroups.com

Nice example Emily – thanks for putting it together!

--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en

Dawn Wolthuis

unread,
Jan 24, 2012, 9:51:40 AM1/24/12
to intersy...@googlegroups.com
Thanks Emily! 

We work with both delivered and custom components a lot. While I like writing simple custom components with MVBASIC and hope to learn more about them, I do not yet grok composite components. Maybe you guys will have some tips on that in the future. 

We have two composite components, neither of which I wrote, which might be why I do not understand them. We have not yet figured out things like onchange and other event handlers, so these composite components do not work like regular components yet (as we are not coding them with all features they need, we are figuring). Our current approach is not to use composite components until we better understand them. So, we subclass existing components and create new components from scratch, but even when it seems obvious that what we would like is a composite component, we avoid that.

For example, we have a timeSelect composite that has two comboxbox components, one for the hours and one for the minutes. In the page where we use it, we want to put an onchange on it, like we might on a single combobox, but we do not know how to code that. I'll admit that I have not spent hours and hours trying to figure this out, and I have received some hints in the past from the Zen list (I'll have to put my finger on those) that I passed along, but no joy on this front yet.  Any suggestions would be great, even if saved for a future tip of the week.  Thanks again!  --dawn

--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en



--
Dawn M. Wolthuis

Take and give some delight today

Jason Warner

unread,
Jan 24, 2012, 11:32:25 AM1/24/12
to intersy...@googlegroups.com, Dawn Wolthuis
Dawn,

Composite components are just containers for other Zen components. If you want your composite component to raise an onChange event, you will need to add that event to your composite component (I can't remember what the syntax is, but it is a property of the component that has a specific type). Then you subscribe to the onChange of your two inner components and from that event, raise the onChange for your composite component. That way, you effectively bubble that event up from you inner controls to the onchange="someHandler()" in your Zen XML.

Hopefully this makes sense, but I remember composite controls being really easy.

Jason

On 1/24/2012 7:51 AM, Dawn Wolthuis wrote:
Thanks Emily!�

We work with both delivered and custom components a lot. While I like writing simple custom components with MVBASIC and hope to learn more about them, I do not yet grok composite components. Maybe you guys will have some tips on that in the future.�

We have two composite components, neither of which I wrote, which might be why I do not understand them. We have not yet figured out things like onchange and other event handlers, so these composite components do not work like regular components yet (as we are not coding them with all features they need, we are figuring). Our current approach is not to use composite components until we better understand them. So, we subclass existing components and create new components from scratch, but even when it seems obvious that what we would like is a composite component, we avoid that.

For example, we have a timeSelect composite that has two comboxbox components, one for the hours and one for the minutes. In the page where we use it, we want to put an onchange on it, like we might on a single combobox, but we do not know how to code that. I'll admit that I have not spent hours and hours trying to figure this out, and I have received some hints in the past from the Zen list (I'll have to put my finger on those) that I passed along, but no joy on this front yet. �Any suggestions would be great, even if saved for a future tip of the week. �Thanks again! �--dawn

On Mon, Jan 23, 2012 at 6:13 PM, Emily Haggstrom <Emily.H...@intersystems.com> wrote:

Today�s tip will cover some useful techniques as you develop more full-scale Zen applications. Zen allows you to create custom components and composites to capture some of your own commonly used features.

�

For instance, let�s say you have a tablePane on one of your pages:

�

<tablePane�id="table"�
����������� caption="This is a tablePane"
����������� tableName="ZENDemo_Data.Employee"
����������� useSnapshot="true"
����������� showQuery="true"
����������� showFilters="true"
����������� fixedHeaders="true"
����������� bodyHeight="15.0em"

����������� filtersDisabled="false"
����������� autoExecute="true"
����������� showZebra="true"
����������� pageSize="10"
����������� showRowNumbers="true"
����������� valueColumn="ID"
����������� maxRows="1000"
����������� useKeys="true">
<column�colName="ID"�hidden="true"/>
.

.

.

<column�colName="Salary"�width="20%"/>
</tablePane>

�

You will probably use these same attribute definitions on many of your pages. To save on development time and add consistency to your application you can create a reusable component with these attributes. The <tablePane> component is an instance of %ZEN.Component.tablePane, and all of the attributes are properties of the class. You would start by subclassing the library class, then add an initial value for any properties you want to set. Dawn Wolthuis sent out a great example of this a couple of weeks ago, if you�d like to see an example �from the field�.

�

Class�MyZEN.tablePane�Extends�%ZEN.Component.tablePane
{
Property�useSnapshot As�%ZEN.Datatype.boolean�[ InitialExpression�= 1�];
Property�showQuery As�%ZEN.Datatype.boolean�[ InitialExpression�= 1�];
Property�showFilters As�%ZEN.Datatype.boolean�[ InitialExpression�= 1�];
Property�fixedHeaders As�%ZEN.Datatype.boolean�[ InitialExpression�= 1�];
Property�bodyHeight As�%ZEN.Datatype.length�[ InitialExpression�= "15.0em"�];
Property�filtersDisabled As�%ZEN.Datatype.boolean�[ InitialExpression�= 0�];
Property�autoExecute As�%ZEN.Datatype.boolean�[ InitialExpression�= 1�];
Property�showZebra As�%ZEN.Datatype.boolean�[ InitialExpression�= 1�];
Property�pageSize As�%ZEN.Datatype.integer�[ InitialExpression�= "10"�];
Property�showRowNumbers As�%ZEN.Datatype.boolean�[ InitialExpression�= 1�];
Property�valueColumn As�%ZEN.Datatype.string�[ InitialExpression�= "ID"�];
Property�maxRows As�%ZEN.Datatype.integer�[ InitialExpression�= "1000"�];
Property�useKeys As�%ZEN.Datatype.boolean�[ InitialExpression�= 1�];

}

�

*NOTE: Use 1 and 0 instead of �true� and �false�. Client-side code expects string booleans, server-side code expects numeric booleans.

�

To reference this on a page, you need to define an xml namespace to identify your components by. This is usually a URL associated with your application to ensure that you don�t use the same namespace as someone else, but it�s really just a string. Add your namespace to the NAMESPACE parameter of the custom component class. You can use the same namespace for all of your components.

�

Parameter�NAMESPACE = "www.myApplication.com";

�

You need to define a tag for components from your namespace to differentiate them from the default components. You can add your namespace declaration to the page tag to do so.

�

Class�MyApp.CustomTableTest�Extends�%ZEN.Component.page
{
XData�Contents [XMLNamespace="http://www.intersystems.com/zen"]
{
<page�xmlns="http://www.intersystems.com/zen"�xmlns:myzen="www.myApplication.com">
<myzen:tablePane�tableName="Sample.Person">
<column�colName="%ID"/>
<column�colName="Name"/>
<column�colName="FavoriteColors"/>
</myzen:tablePane>
</page>
}
}

�

Note that you still need to include the column definitions. Those are additional components.

�

If there is a whole set of components you reuse frequently, you can define a composite component. Let�s say the whole table from the previous example shows up on a bunch of your pages. You can save it as a custom component like this:

�

Class�MyZEN.personTable�Extends�%ZEN.Component.composite
{
Parameter�NAMESPACE = "www.myApplication.com";

XData�Contents [XMLNamespace="http://www.intersystems.com/zen"]
{
<composite�xmlns:myzen="www.myApplication.com">
<myzen:tablePane�tableName="Sample.Person">
<column�colName="%ID"/>
<column�colName="Name"/>
<column�colName="FavoriteColors"/>
</myzen:tablePane>
</composite>
}
}

�

A composite has an XData Contents section, just like a Zen page, but there�s no <page> component. Note that you�ll have to add your namespace to the <composite> tag if you�re using any custom components in the composite.

�

Using the composite component my page now looks like this:

�

Class�MyApp.CustomTableTest�Extends�%ZEN.Component.page
{
XData�Contents [XMLNamespace="http://www.intersystems.com/zen"]
{
<page�xmlns="http://www.intersystems.com/zen"�xmlns:myzen="www.myApplication.com">
<myzen:personTable/>
</page>
}
}

�

Custom components and composites can also be used to help define a consistent look and feel for your application. You can add an XData Style block to either class. A good starting point is to find the style tags from the parent classes and copy them into your custom class. Then you can override the defaults with whatever you desire. Changes will automatically be applied to any classes that use your component.

�

For further reading and even more examples, check out this chapter in the documentation. Enjoy!

http://docs.intersystems.com/cache20111/csp/docbook/DocBook.UI.Page.cls?KEY=GZAP_customization

--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en



--
Dawn M. Wolthuis

Take and give some delight today

Tony Gravagno

unread,
Jan 24, 2012, 6:24:25 PM1/24/12
to InterSy...@googlegroups.com
From: Dawn Wolthuis
We work with both delivered and custom components a lot. While I like writing simple custom components with MVBASIC and hope to learn more about them, I do not yet grok composite components.. 
Web components like this are a huge, multi-billion dollar industry.  The rest of the world has enjoyed controls for almost all languages for the last 15 years or so.  I Wish in the MV space there were more appreciation for such things as I would seriously enjoy cranking out a ton of these.  Unfortunately with little to no interest in third-party offerings (completely unlike every other industry), MV developers are doomed to writing everything they want from scratch.
 
My position, shared with millions of others, is that it's more important for developers to spend their time on app functionality rather than on components which are often re-written many times over in each shop.  Sure it's critically important for a platform like Zen to include the ability to create custom components along with a wealth of built-in controls, but typically this will only be used for simple extensions of basic functionality, and individuals will generally not take it upon themselves to write more complex components like those enjoyed elsewhere.
 
This situation limits the scope of Zen for larger projects.  Newcomer developers from other environments can easily ask "where are the tools?" and "why should I hand-code all of this, or go without functionality when I can get this kind of stuff easily elsewhere - and a lot of it for free?"
 
I'm presenting this (certainly arguable) view for a few reasons.
 
First, when you Zen developers can't find something you want, post a note here.  Someone else may already have it or may be willing to create it.
 
Second, when faced with a challenge, consider your time to make versus buy.  How much is your time worth?  Will it actually cost you more to not pay for something that you need to write yourself?  Consider paying a little something for work that someone else does which will save you time.
 
Third, and finally, I'm guessing that most developers would prefer to (a) not write a complex component _and_ (b) not purchase one either.  "We don't really need that, we can do with this..."  The result being an end-user offering that pales in comparison to others.  This makes it even less appealing for developers to use this platform than others because the final product is not as marketable.  I don't say this to offend the platform but to encourage developers to make better use of it, and to foster an industry which is more likely to benefit everyone.
 
Now after all of that, to our ISC friends: Where Infragistics or Telerik or Syncfusion provide complex components for ASP.NET developers, does anyone out there yet provide similar tools for Zen?  If so, there ya go, make or buy.
 
Regards,
T
 
Tony Gravagno
Nebula Research and Development
TG@ remove.pleaseNebula-RnD.com
Nebula R&D sells Pick/MultiValue products worldwide,

Dawn Wolthuis

unread,
Jan 24, 2012, 8:49:28 PM1/24/12
to intersy...@googlegroups.com
On Tue, Jan 24, 2012 at 5:24 PM, Tony Gravagno <dbkv...@sneakemail.com> wrote:
From: Dawn Wolthuis
We work with both delivered and custom components a lot. While I like writing simple custom components with MVBASIC and hope to learn more about them, I do not yet grok composite components.. 
Web components like this are a huge, multi-billion dollar industry.  The rest of the world has enjoyed controls for almost all languages for the last 15 years or so. 

Yes, so pretty darn cool that MV folks using Cache' can do likewise. We can use components written in MVBASIC or COS, as well as client-side portions in JavaScript. With Cache' we can plan in a bigger sandbox to some extent.
 
I Wish in the MV space there were more appreciation for such things as I would seriously enjoy cranking out a ton of these.

That would be awesome, of course!
 
Unfortunately with little to no interest in third-party offerings (completely unlike every other industry),

Yes, this is definitely an issue.
 
MV developers are doomed to writing everything they want from scratch.

Not I, said the duck. I try to use out-of-the-box components from InterSystems either directly or by subclassing them, although we have written some that might be considered more "application code" (more specific components) by scratch.
 
 My position, shared with millions of others, is that it's more important for developers to spend their time on app functionality rather than on components which are often re-written many times over in each shop.

Yes, but components are also a powerful way to develop reusable code. For example, we have a custom component that has a bunch of information about a single entity. We can use that on a web page, in an email message, or in a search result with multiple such "stamps" on a page. This component would definitely not be developed by a component developer abstracted from the application. 
 
  Sure it's critically important for a platform like Zen to include the ability to create custom components along with a wealth of built-in controls, but typically this will only be used for simple extensions of basic functionality, and individuals will generally not take it upon themselves to write more complex components like those enjoyed elsewhere.

Well, some people might, but I'm a peasant that way ;-) 

The good news is that in addition to ISC folks and people on the Zen list, professionals like David R and Jason W have provided me with example code which I have very much appreciated.
 
 This situation limits the scope of Zen for larger projects.

No, it doesn't. [big grin here]
 
  Newcomer developers from other environments can easily ask "where are the tools?" and "why should I hand-code all of this, or go without functionality when I can get this kind of stuff easily elsewhere - and a lot of it for free?"

Yes, I suspect you are right on this point to some extent.
 
 I'm presenting this (certainly arguable) view for a few reasons.
 
First, when you Zen developers can't find something you want, post a note here. 

Well, usually we post it on the Zen list. 
 
Someone else may already have it or may be willing to create it.

Yes, we have been helped many times and try to also provide some help to others. It is a good community.
 
 Second, when faced with a challenge, consider your time to make versus buy.  How much is your time worth?  Will it actually cost you more to not pay for something that you need to write yourself?  Consider paying a little something for work that someone else does which will save you time.

Your typical TG ad, right? Yes, I agree that given the funds it might very well be worth it.
 
 Third, and finally, I'm guessing that most developers would prefer to (a) not write a complex component _and_ (b) not purchase one either.  "We don't really need that, we can do with this..."  The result being an end-user offering that pales in comparison to others. 

Yes.
 
This makes it even less appealing for developers to use this platform than others because the final product is not as marketable. 

Potentially, yes. Simple to the user can be very hard to write.  If you want to write solid, simple user interfaces you might be well served to ditch some of the drag and drop complexities, however. For a specific purpose, I have watched a lot of people use the computer, both young (3 being the youngest) and old (82 being the oldest). What surprised me is that even college students get confused by many drag and drop interfaces, although no one seems to be confused by Angry Birds after they see it once. There are some places where I would definitely like more sophisticated components or would like to be able to use jQuery fluidly (perhaps just my ignorance that is holding me back).
 
I don't say this to offend the platform but to encourage developers to make better use of it,

Hey, we are trying brother. We are finally moving out of quirks mode (we didn't want to go there in the first place) and away from table-based layout, and we will eventually get graphic designers involved so it can have a more professional look.
 
and to foster an industry which is more likely to benefit everyone.
 
Now after all of that, to our ISC friends: Where Infragistics or Telerik or Syncfusion provide complex components for ASP.NET developers, does anyone out there yet provide similar tools for Zen?  If so, there ya go, make or buy.

If ASP.NET every seems to be a far better platform, we could use that with Cache' in place of Zen, but I'm no longer in the massive M$ world for a reason. There are pros and cons to every decision. Cheers!  --dawn
 
 
Regards,
T
 
Tony Gravagno
Nebula Research and Development
TG@ remove.pleaseNebula-RnD.com
Nebula R&D sells Pick/MultiValue products worldwide,

--
You received this message because you are subscribed to the Google Groups "InterSystems: MV Community" group.
To post to this group, send email to Cac...@googlegroups.com
To unsubscribe from this group, send email to CacheMV-u...@googlegroups.com
For more options, visit this group at http://groups.google.com/group/CacheMV?hl=en
Reply all
Reply to author
Forward
0 new messages