Archive

Posts Tagged ‘Control’

XSnippet: ViewEntries ohne repeat-control in XPage durchloopen

20/12/2011 3 comments

Hallo,

ich hatte heute ein kleines Problem. Die Lösung habe ich als XSnippet veröffentlicht und werde ich hier etwas genauer erklären:

Problem war das folgende:

Ich hatte ein kleines Modul, welches die Bilder von diversen Mitgliedern einer Community anzeigen sollte. Das ganze sollte auch immer zufällig passieren, also dass ich an jeder Position immer andere Mitglieder sehen würde. Leider war es aufgrund der Struktur und des Aufbaus des Moduls nicht möglich ein repeat-control zu verwenden. Daher folgender Lösungsansatz:

Speichere einen Iterator im Hintergrund und greife an jeder benötigten Stelle mit iterator.next() darauf zu.

Ich habe das mal ausprobiert, und siehe da, es funktioniert und ist performanter als gedacht.

Im DataContext der XPage (so etwas wie eine lokale Variable einer XPage, auf welche ich einfach per SSJS zugreifen kann) compute ich meinen Iterator, so zum Beispiel:

var tempTreeMap:java.util.TreeMap = new java.util.TreeMap();
var tempColl:NotesViewEntryCollection = allActiveUsers.getAllEntries();
var tempEntry:NotesViewEntry = tempColl.getFirstEntry();
var tempCollection:java.util.Collection = null;

while (tempEntry != null) {
tempTreeMap.put(@Unique(), tempEntry.getDocument());
tempEntry = tempColl.getNextEntry(tempEntry);
}

tempCollection = tempTreeMap.values();
return tempCollection.iterator();

Somit liegt schonmal ein Iterator im Hintergrund. Nun kann ich in jedem verwendeten image-control mit iterator.next() darauf zugreifen und mir das Dokument holen, welches in der dazugehörigen TreeMap liegt um mir die URL des Bildes zu berechnen.

Natürlich muss abgefangen werden ob es noch ein nächtes Element im Iterator gibt auf welches ich zugreifen möchte, um diese kleinen hässlichen Null-Pointer Exceptions zu vermeiden.

Hier das Snippet:
XSnippets

Advertisements

XPages: Useability – Parameter mit Aliaswerten in Custom Controls

Heute mal ein kleiner Tipp, welcher die Useability von Paremetern in selbst gebauten Custom Controls erhöhen kann.

Man kann für Custom Controls ja Parameter definieren, dies tut man in den Eigenschaften des Elements xp:view (root-Element des Controls) unter Property Definition.
Dort hat man die Möglichkeit für einen Parameter den Editor (die Art wie man bei der Einbindung den Parameter angibt) auf ComboBox zu setzen und dort mehrere Einträge mitzugeben, welche man dann bei der Einbindung in eine XPage oder ein anderes Custom Control auswählen könnte.

Natürlich möchte man es sich und anderen möglicht bequem machen und dort sprechende Vorgabewerte eintragen, damit man weiß was diese jeweils bedeuten. Dies ist auf der anderen Seite natürlich schlecht im Programmcode handlebar. Daher kann man einfach Aliaswerte benutzen.

Hier ein Beispiel:

Parameter 1 wird im Menü über eine ComboBox ausgewählt. Folgende Vorgabewerte werden angeboten:

0|Wert 1
1|Wert 2

Hier muss man mit dem Alias leider anders herum arbeiten als man es von Notes her gewohnt ist. Der Wert vor der Pipe (“|”) ist der Wert der tatsächlich übergeben wird, den man dann auch mittels compositeData azurückgegeben bekommt. Der zweite Wert dahinter wird dem User im Menü angezeigt.
Achtung: Dies ist lediglich eine optische Geschichte, d.h. der Aliaswert wird nur im Menü verwendet. D.h., wenn man den Parameter mit Aliaswerten berechnen möchte, so muss man wieder den richtigen Wert, welcher vor der Pipe angegeben wurde benutzen und zurückliefern.

Lediglich eine kleine optische Spielerei, erhöht aber den Komfort beim Benutzen von eigenen Custom Controls.

XPages: FileUpload Control – replace filename

08/11/2011 1 comment

Today only a little advice.

I had the problem that some uploads failed in an application from time to time. I have used the standard FileUploadControl.

Unfortunately, the error wasn’t really reproducable, therefore I had to do some experiments.

A possible reason for this error were umlauts (we have them in germany, Ä, Ö, Ü) in the filename.

You can change the filename with a standard function of the control, it’s called “Replace file name of uploaded file with the following name”. You can find it in the main properties of the control.
You can also compute that, that works with the following code:

var path:com.ibm.xsp.http.UploadedFile = getComponent("fd_file").value;
var newPath:string = path.getClientFileName();

newPath = newPath.replace("Ä", "ae");
newPath = newPath.replace("Ö", "oe");
newPath = newPath.replace("Ü", "ue");
newPath = newPath.replace("ä", "ae");
newPath = newPath.replace("ö", "oe");
newPath = newPath.replace("ü", "ue");

return newPath;

There nothing special about that, except the class com.ibm.xsp.http.UploadedFile. This class is, in good old IBM manner, not documented. This class gives you some nice possibilities to access the uploaded file, before it is saved in a document.

Here is another interesting article about this topic: XPagesWiki

XPages: Collection of advices

Hi folks,

here is a small collection of some hints which were written by my colleagues and myself throughout time.

Naming of attributes in Internet Explorer

It seems, in the Internet Explorer, Dojo has some problems finding the correct element, while usingattribute selectors, if there is a string reserved by the system in the attribute. (e.g. name or id). Because Dojo uses the selector engine “Sizzle” like JQuery, the same phenomenon can appear using JQuery.

An example for that is an input-field with the name “username”. If you select dojo.query(‘input[id$=”WFApprovalVFL”]’) the field “username” will be selected, too, although it doesn’t end with WFApprovalVFL.

The same happens with keynames in JSON-objects.

Not rendered datasources will always be computed

If you use a datasource in a custom control, the code of the datasource will always be computed, no matter whether you set rendered or loaded to false. The code will always be computed. This could lead to errors hard to track down.

Furthermore, if you use several datasources in different custom controls, which point to the same document, all these datasources will be saved and, eventually, the document is saved more than once with saveing conflicts. To avoid this, you can reference the datasource in your custom controls directyl via the name, or you can pass on the datasource via a parameter of the custom control (compositeData). Therefore you have to select the class of the datasource, which doesn’t appear in the list of available types. The name of the class of a datasource is com.ibm.xsp.model.ModelDatasource.

Check whether a viewPanel is categorized

If we have a view control in our XPage which name is viewPanel1 the following code:

var model:com.ibm.xsp.model.domino.DominoViewDataModel = getComponent("viewPanel1").getDataModel();
return model.getCategoryIndentLevel();

returns the value 0 if view is categorized, it returns -1 if not.

Use case: If you sort a view, the content of a categorized column gets lost. With that you can check whether the view was sorted and reset the view.

Avoid the onChange bug in Internet Explorer when clicking on a CheckBoxGroup

If you use RadioButtonGroups or CheckBoxGroups in an XPage or a custom control, you could face the problem in the Internet Explorer, that after a partial refresh the submitted values of the group are the values from a previous request. This occurs if you click the label of instead of the box, directly. The reason is that the IE submits the partial refresh before setting the new value from the UI.

rendered="#{javascript:context.getUserAgent().isIE()}"


Example
:

There is a CheckboxGroup with the options A, B, C and D. In the onChange event, a partial refresh will be fired on another panel, which hides or shows some elements in dependence of the chosen value. If you click the label for Option A, there is no submitted value. If you click the label of option B, the value A is submitted. If you click after that on the label of option C, Ab and B will be submitted.


Workaround
:

You can fire the partial refresh a second time in the onComplete event of the onClick event.

 <xp:this.onComplete>
<![CDATA[XSP.partialRefreshPost("#{id:refreshPanelID}");]]>
</xp:this.onComplete>

The workaround above doesn’t work if there are additional actions or server-side code. The code will be executed only on the first refresh. To get this event-handler working again, you have to hang out the click-event from the standard-action and execute it by yourself. You can achieve that with a scriptblock (The name of the control is Output-Script, you can find it if you open the list of other controls in the sidebar of the Domino Designer) Because the checkbox itself is inside the label, you have to seperate it from the own execution.

 <xp:scriptBlock id="scriptBlock1"
        rendered="#{javascript:context.getUserAgent().isIE()}">
        <xp:this.value><![CDATA[dojo.addOnLoad(function(){
    dojo.query("label",dojo.byId("#{id:checkBoxGroupID}")).forEach(function(el){        
        dojo.connect(el,"onclick",el,function(e){
            if (e.target.type != "checkbox") {
                e.preventDefault();
                dojo.query("input",this).forEach(function(el){
                    dojo.attr(el,"checked",!(dojo.attr(el,"checked")));
                });
            }    
        });
    });        
});]]></xp:this.value>
</xp:scriptBlock>

Another advantage of this method, compared to workaround 1, is that you don’t need a second request.

Validation of two dependen input-fields

While validating two fields dependent of each other, you have to read the value of the field which is validated. If you compare the value of the second field, validation will not be fired after the first fail and the validation error persists.

Example:

 <xp:inputText id="recipientNotesID"
   value="#{test.recipientNotesID}"
   disableClientSideValidation="true" required="true">
   <xp:this.validators>
      <xp:validateRequired message="Required value."></xp:validateRequired>
   </xp:this.validators>
</xp:inputText>
<xp:inputText id="recipientNotesPW"
   value="#{test.recipientNotesPW}"
   disableClientSideValidation="true" required="true">
   <xp:this.validators>
      <xp:validateExpression>
         <xp:this.expression><![CDATA[#{javascript:((getComponent("recipientNotesPW").getSubmittedValue()||"")!=(getComponent("recipientNotesID").getValue()||""))}]]>
         </xp:this.expression>
         <xp:this.message><![CDATA[#{javascript:"Values must not be equal."}]]></xp:this.message>
      </xp:validateExpression>
      <xp:validateRequired message="Required value."></xp:validateRequired>
   </xp:this.validators>
</xp:inputText>

Stumbling Stone: FileUpload-Control

Today I had a tiny problem. Not even a bug, only a small booby trap.

On my page, I had three FileUpload controls and one FileDownload control. It was specified that a user can upload a maximum of three attachments. Therefore I added a rendering condition to all FileUpload controls, which chekcs the number of attachments in the document.
WARNING: The formula @Attachments doesn’t seem to work properly. It seems like @Attachment only checks the backend-document. I want to know how much attachments were uploaded right now to constrain the possibility to upload something. The function “doc.getAttachmentList(‘feldname’).size()” saved my day.

The three controls are placed below another, the first will be hidden if there are thee attachments, the second if there are two and the last one if there is at least one attachment. All this linked to a refresh, which is fired when you delete one attachment, everything works fine.

However, I faced the effect, if I add 3 attachments at once, only two were saved. The attachment from the last FileUpload control was never saved.

Get ready for the reason:

Controls seem to be processed sequential, connected with an internal refresh. That means, the first control is processed and the file is uploaded -> new there is a refresh -> second control is processed, everything is fine, so the second attachment is uploaded -> there is a refresh again -> third control wants to be processed, but there is more than one attachment in the document, so the control is not rendered anymore, therefore, the third attachment goes to hell.

The solution is quite easy, you only have to reverse the order of the number of attachments in the render condition. That means, the first control should be hidden if there is more than one attachment, the second is hidden with two attachments and the third with three attachments. Because the controls are processed in order they are in the code, everything works fine.

Another interesting fact is, that if you have some mandatory fields or have another server-side validation on your form, attachments are uploaded when you click the save button. After that the validation yells. The backend document doesn’t get bothered, but in the frontend document, there are your attachments uploaded, yet. In the context of my problem above, this could be quite confusing, but if you know that fact you can work around that.

XPages: Control-hierarchy

A small advice for the horror we call XPages

This is a page which I use from time to time. It shows the hierarchy of the controls you can use in your XPages: Control Hierarchie

But not only the standard-controls, it also shows the controls from the Extension Library, which I would recommend to you: ExtLib

%d bloggers like this: