Skip to main content

Posts

Custom Control Design Definition Tricks

I think by now many people are aware of the Design Definition you can set when creating a custom control. Here is a quick refresher if you are not. A design definition simply replaces what you see when you drop the control on an xpage. By default, it shows whatever is in your control, but this property can be used to replace that with: documentation about how to use the control, for example what custom properties mean or other requirements such as using a data source named "document1" A visual short-hand, for example a control could just show <Header Control> instead of everything inside. This is great for minimizing clutter in the designer and it can also speed up the loading/rendering of the xpage in designer. An interactive tool that allows you to drop additional controls inside  There are a couple of advanced features that can be tricky to figure out unless someone shows you. Here is one:

Problem with naming a custom property "size"

I ran into this issue today and thought I'd share: I created a custom control, and for that custom control I created a few custom properties. One of these properties was unfortunately named "size". There isn't any warning that size would be a bad name for a property, but that causes a problem. It causes a problem because compositeData is just a Map, and size is a method of Map. So what you wind up getting for some reason, is the entire javascript array instead of the value you are looking for. Something like this: {size=md, label={columns=2, text=test}, input={dataBinding=null, columns=10}} I haven't tested it, but I suspect it would be the same with properties named values and clear, among others. However, if you rename the size property, everything works just fine.

Quick Tip: Content-Disposition

I ran into a problem that it took me a few hours to figure out, so maybe I can spare someone the headache. I'm creating a file using POI and streaming it to the browser. It was working great in Firefox, but in Internet explorer if I opened the file instead of saving it, the file name was xAgent_PrintForm.xsp and not the correct Form.docx . If I saved the file, it had the correct file name. Even worse, it had been working fine before and just started happening without any explanation. It turned out to be a header in my response writer.

Quicktip: Elements need IDs to attach client-side events

I ran across something today that took me a few minutes to figure out, so I thought I'd share it. I was trying to make a column heading toggle the display of the column below when clicked. So I wrote up a quick function like this: function toggleDivDisplay(divId) { // call with toggleDivDisplay('#{javascript:getClientId("**XspIdHere**")}'); var div = document.getElementById(divId); if (div.style.display == "") { div.style.display = "none"; } else { div.style.display = ""; } } This function was called from the onclick event for the heading Div I had created, and everything worked swimmingly. However when I used the same technique on a different column, it failed. I spent a few minutes making sure the target ID matched what I was sending, and sure enough it did, and I was left scratching my head. That was when I realized how client-side JS is actually attached: it isn't added to the HTML element itself. A ...

Move all your code into script libraries

Here is a little tip and the reason behind it: If you have any code on an XPage, replace it with a single function call and move the code to a script library. Example: If you have code like this on your XPage <xp:this.querySaveDocument><![CDATA[#{javascript: var foo = "hi"; var bar="there"; return (foo==bar?True:False);}]]></xp:this.querySaveDocument> Replace it with this <xp:this.querySaveDocument><![CDATA[#{javascript: return foobarQuerySave();}]]></xp:this.querySaveDocument> And create and include a script library with this function foobarQuerySave() {    var foo = "hi";    var bar = "there";    return (foo==bar?True:False); } Even if there is no code there currently, if you think there may ever be a need for it you should add a stub function that just returns true and call it. Here's why: