bookmark_borderQUIND: Profile documents: sort of ;-)

I’m sure you also need sort of “profile documents” once in a while. Documents where a user can store some values he wants to use over and over again, in Web technology term thing of a “cookie”.

This is plain easy!

Simply open the xPage and as a Data source document id (red box) define a computed value like this:

Document ID code:
var doc:NotesDocument = database.getView(“lupUserProfiles”).getDocumentByKey(session.getEffectiveUserName(), true);
if( null != doc ){
return doc.getUniversalID();
}

that way the xPage will either be displayed empty (when no such “profile” document exists) or it will use the appropriate user profile it finds.

In the QuerySave (or somewhere else) you need to make sure to save the user name and have it in the view as sorted first column of course

QuerySave code:
try{
var doc:NotesDocument = docCurrent.getDocument();
var item:NotesItem = doc.replaceItemValue(“userName”, session.getEffectiveUserName())
item.setAuthors(true);
}catch(e){
// handle error
}

bookmark_borderYOUFEB: anyone else being mad about the copy&paste (via keyboard / not working in designer?

I am getting over and over mad that copy & paste is not working well at all in the LN designer especially when dealing with xPages stuff..

I add a template inheritance to a design element, select it, copy via <ctrl><c> and paste it onto another design element, either I get something pasted i copied long time ago, or nothing at all.

so I have to revert to right click copy and right click paste..

this annoys me a lot.. is it just me or anyone else facing the same issue?

bookmark_borderError 500: your thoughts?

Developing xPages i’m sure you also have come across those nasty “Error 500” errors.

This bugs me right now. The error.log I get won’t help me at all.

Any ideas how to easier figure out the problem?

In my case the error.log simply states: “Unable to find component with ID xyz”.

Interestingly: the component IS visible.

I am a bit lost here: this happens in my xPage only when I copy the contents (some of them) to a new document which is then redirected to and opened in edit mode.
If I create the new document afresh all works as it should.
If I “copy all Items” to the new document then it also works fine.

any ideas?

bookmark_borderBUG in Lotus Notes applications: saving documents with private folders (not stored on desktop) and folder references enabled

Long time no see, but stay tuned, there will be more updates again soon regarding the xPages development from my side.

This week we have a very nasty bug. When people tried to save documents they got an “You are not authorised to perform that operation” error message.

After a while fiddling around we figured: We copied&pasted documents we could save the newly copied documents. So where was the difference? We used TeamStudio Delta to figure out differences between the two documents. It turned out mostly just the “Folder References” fields.

I googled and surely enough found this bug report: http://www-01.ibm.com/support/docview.wss?rs=463&uid=swg21099783

It basically states that users do get this error when folder references are enabled and the documents are stored in private folders which are not stored on the desktop.

maybe this information helps anyone out there to not “desperate” if faced with a similar issue.

yours

Michael

bookmark_borderHAPPY!!! first full featured xPage application productive!

I am happy to report that our first full featured (integrated workflow, cool typeAheads, fantastic validation, dynamic tables and many more features) is fully productive!

Thanks to all readers and commenters on my blog and all other bloggers out-there giving me help and insight into the deeper workings of the xPages.

Summarized main difficulties:

  • getting the validation to work the way we required (ie. without needing ExtensionLibrary tabbed tables, all fields should be validated, even if currently invisible and the validation should be customizable by the customer himself)
    • Solution was: not using validators at all, simply prevent the save with a condition on the action group in the save buttons, the condition is a “result” from our custom validator which sets JSF messages where appropriate
  • customized typeAheads (see this blog)
  • workflow integration (we can continue to use the LN client based code, which is important as the interface is now working on both “clients”, notes and web)
  • certain parts of the form stored in different documents (see this blog)
  • dynamic tables which lets the user add new rows to tables of data
  • simple yet full featured and customizable views, using the DynamicViewPanel with different filter options per selected view, customizable (via styles) view columns
  • fancy field help (see this blog)
Result:
What we now have is a full featured framework which will help us create future xPage applications in a fraction of the time spent on this one! As a matter of fact we could create a simple form/view db with full featured workflow within one day!!!!!!!!!!!!! Most of the work actually could even be “outsourced” to the customer, work such as “defining” field help, column customizations, validations etc.
Best features in xPages (imho):
  • CustomControls!!! change in one place an all occurrences are updated! Subforms in the old LN days were no match at all!!!
  • typeAheads
Worst feature in xPages (imho):
  • error messages from server: an HTML 500 error is of no use, sometimes I needed to dissect the whole app again to find where the problem was
  • OneUI: it’s a pain in the ass, but we did it, to figure out how to properly change certain GUI elements look and feel (such as typeAheads)
Recommendation:
  • don’t use JavaScript (or only to call backend Java code) !!!! debugging JavaScript is a pain in the ass where as debugging Java is so straight forward (see this blog) and the speed of the code execution is SOOOOOOOOOOOOOOOOOOOOO freaking fast!!!
  • use where ever possible “static” methods so you don’t need to instantiate the class, eg. our StandardUtil class has ONLY static methods such as: getKeywordValues, searchUser (for typeAhead), getSortedDocumentCollection, getEmptyDocumentCollection, hasAccess, hasRole etc.
I now need some rest. The past few weeks were mostly sleepless. Any recommendation for a nice “get-well-again” resort close to Switzerland are welcome 😉 ! (can be south Germany or Austria as well)

bookmark_borderINDIP: xPages isEditable() won’t work on panels with READ ACL! see my workaround

If you have workflow applications then it’s most likely that you wanna make certain parts of your xPage READonly for certain states (eg. such that an approver cannot change the details of the request he has to approve)

In old days we used access controlled sections. xPages gives us the possibility to add ACLs to panels, that servers (almost) the same purpose.

Why only almost? Cause all elements you put there to set data (buttons, links etc.) won’t be hidden even if you use currentDocument.isEditable().

Here’s my workaround:

on the Visible property of such a button etc.
instead of just:
currentDocument.isEditable()

use:
currentDocument.isEditable() && !YourClass.hasParentReadACL(getClientId(this.getId()))

now create a YourClass (we use our StandardUtil as it contains “standard” methods) and add this method:

public static boolean hasParentReadACL(String id) {
String[] components = id.split(“:”);
UIComponent parent = null;
String parentId = null;
int i = 2;
// the || is important as repeat controls within custom controls use the same id, so we have to
// get their parent as unique parent
while (null == parent || parent instanceof XspDataIterator) {
parentId = components[components.length – i++];
parent = JSFConnector.findComponent(parentId);
}

UIViewRoot root = FacesContext.getCurrentInstance().getViewRoot();
boolean hasACL = false;

while (root != parent) {
if (parent instanceof UIPanelEx) {
if (null != ((UIPanelEx) parent).getAcl()) {
hasACL = true;
break;
}
}
parent = parent.getParent();
}

return hasACL;
}

and voila all your additional buttons etc. are hidden if one of the parent panels has an ACL!
Of course you might change the code to really check for a READ ACL. We only use ACLs for READ so this check is at the moment superfluous.

ah.. a not so minor thing: we define the StandardUtil in a SSJS library to easy reference StandardUtil, in your case you may wanna use:
&& com.yourcompany.YourClass.hasParentReadACL()

bookmark_borderQUINDIP: format your dates from backend documents properly

we use a standard date format in our company: 2013-04-30 22:52

to accomplish this I use:

When you simply use a data binding this works like a breeze.
It’s a bit more complicate if you want to display a date/time from a backend document with Java

 this won’t work:

doc.getItemValueString(“fieldName”)
doc.getItemValue(“fieldName”).get(0)
doc.getItemValueDateTimeArray(“fieldName”).get(0)

this will work:
doc.getItemValueDateTimeArray(“fieldName”).get(0).toJavaDate()

and just as a side note: I really feel stupid! it took me hours to figure out how to get it to work!!! and yet once I understood why it’ became so crystal clear

bookmark_borderYOUFEB: DynamicViewPanel cannot sort descending?

I have a been troubling why I can’t sort on certain columns. Again after a loooooooooooooooooong time I figured: hell what..

So I changed the sort direction of that column which I could not sort in the dynamicViewPanel. Just out of any other options, something as a “last resort”, or out of desperation.

And who believes it??? Finally I could sort?

So I figured: dynamicViewPanel cannot sort descending?

Anyone can confirm this? Sorting ascending and both directions works, descending nope!

Don’t know if it’s related to the DominoViewCustomizer..

where can I file a bug report?

bookmark_borderYOUFEB: do you want me to share an easy way to configure views in your xPages?

just recently I have found the DominoViewCustomizer to customize the views displayed with the Dynamic View Panel from the extension library.

Of course it was a cool idea but I needed a way to “customize” my views.

Is anyone interested in me sharing this whole “component”? Well it’s not really just one component, a few pieces play together.

If I get a decent amount of comments asking me to share it I will do so.

Just so you know what it would be about:

  • simple way to let users choose from available views
  • in an open view you can call “ColumnCustomizer” which lets you set all properties you can set on a view column
  • additionally some ideas how to add easy filtering on views

I think I would strip down my “framework” to just that piece of functionality 
and put some comments on how to use/implement it online.

I from my side would have question as well:

Does someone know if I can create a (repeat) control which has “computed properties” (eg. the label, or values to choose from) based on not just a simple string but on JavaScript which would be “evaluated” on the fly?

I do know how to evaluate JavaScript with Java, what I am missing though: How can I attach to a new (repeat) component dynamic JavaScript? Dynamic means: the JavaScript is not stored in the component but on a configuration document.

Still confused? An example:
I am looking for a way to fully “customize” my view filter!
I want to put some tags/attributes and some code onto my dynamic column view definitions.
The result would be a fully automated dynamic view filter! Think about dropdownboxes which get their values from the provided JavaScript

At the moment I do have to create in one custom control “hard coded” fields (for each view on a different panel which is rendered only for specific views) for filtering on specific columns. I would like that to be customizable!


bookmark_borderINDIP: sort a document collection in Java (Java heroes may skip this)

Update: the result of the blog below landed here. Thanks to Nathan Freeman, hihi, kudos to me???

In Lotus Script it was not a simple task to sort a document collection. In Java it sort of is.

Idea: use a comparator class, supply with an array of fields upon which the “sorting” should happen and let the Collections.sort do it’s magic:

Comparator class:

public class CollectionComparator implements Comparator<Document> {

String[] sortFields = null;

public CollectionComparator(String[] sortFields) {
this.sortFields = sortFields;
}

public int compare(Document doc1, Document doc2) {

try {
int compared = 0;
// loop all sortFields
for (String field : sortFields) {
Item item1 = doc1.getFirstItem(field);
Item item2 = doc2.getFirstItem(field);
switch (item1.getType()) {
case Item.TEXT:
case Item.AUTHORS:
case Item.NAMES:
case Item.READERS:
String val1 = doc1.getItemValueString(field);
String val2 = doc2.getItemValueString(field);
compared = val1.compareTo(val2);
if (0 != compared) {
return compared;
}
break;
case Item.NUMBERS:
Double d1 = doc1.getItemValueDouble(field);
Double d2 = doc2.getItemValueDouble(field);
compared = d1.compareTo(d2);
if (0 != compared) {
return compared;
}
break;

case Item.DATETIMES:

DateTime dt1 = item1.getDateTimeValue();
DateTime dt2 = item2.getDateTimeValue();
compared = dt2.timeDifference(dt1);
if (0 != compared) {
return compared;
}
break;
}

item1.recycle();
}
return 0;
} catch (NotesException e) {
Logger.logError(e);
}

return 0;
}

}

Calling the sort:
// fill a list with the documents
List<Document> docs = new ArrayList<Document>();
doc = dc.getFirstDocument();
while (null != doc) {
docs.add(doc);
doc = dc.getNextDocument(doc);
}

// sort the list
String[] sortFields = new String[] { “fieldName” }; // you can also supply multiple fields “field1”, “field2”
Collections.sort(docs, new CollectionComparator(sortFields));

// retrieve values
for (Document docSorted : docs) {
values.addAll(docSorted.getItemValue(“Values”));
}
All code samples and downloads are copyright Michael Zischeck and licensed under Apache License 2.0