navigationPath & selection properties

Introduction

Once in a while you move back in time and understand why you have forgotten certain rules. Mostly because you have stopped using them or you experience the same pitfalls as others do and you just want to forget them to move ahead.

navigationPath and selection properties

One of those things are the navigationPath from the Application Layout control and the selection property in it’s navigation nodes.

navigationPath

The navigationPath allows you to control the currently selected titlebar Tab and the selection appearance of any Navigator control on the XPage.

selection

The selection property is nothing more than a regular expression used to select an item. The expression is matched against the navigationPath, described above.

selected

Selected is a property that indicates if a node is selected or not. This property often causes confusion.

Mix them together

So if you mix these properties above you can establish some nice usability improvement for your app-user. It can visualize (via style classes) when a certain titlebar should be highlighted or not.

Example Aap Noot Mies

The follwoing example will demonstrate it’s basic feature (and shows some oddness in the Dutch education system while Mies is nothing more than a cat).

As titlebar tabs I have: Aap, Noot and Mies.

As Navigator nodes I have Aap, Noot, Mies and Apes/Gorilla, Apes/Chimp.

Each Navigator links points to an individual XSP but the last two nodes belong to the Aap titlebar tab.

ccLayout

I have a custom control with the application layout control on it. For the navigationPath property I have set up a propery definition so I can adjust it for eac XSP:

<xe:this.configuration>
<xe:oneuiApplication
navigationPath=”#{javascript:compositeData.navigationPath}”

The titlebar nodes are defined as follwed:

<xe:this.titleBarTabs>
<xe:pageTreeNode label=”Aap” selection=”/Aap/.*”
page=”/aap.xsp” selected=”true”>
</xe:pageTreeNode>
<xe:pageTreeNode label=”Noot” selection=”/Noot/.*”
page=”/noot.xsp” selected=”true”>
</xe:pageTreeNode>
<xe:pageTreeNode label=”Mies” selection=”/Mies/.*”
page=”/mies.xsp” selected=”true”>
</xe:pageTreeNode>
</xe:this.titleBarTabs>

Here I have set a regex for the selection property.

Navigator control

On the same custom control I also have a Navigator control:

<xe:navigator id=”navigator1″>
<xe:this.treeNodes>
<xe:pageTreeNode label=”Aap” page=”/aap.xsp”></xe:pageTreeNode>
<xe:pageTreeNode label=”Noot” page=”/noot.xsp”></xe:pageTreeNode>
<xe:pageTreeNode label=”Mies” page=”/mies.xsp”></xe:pageTreeNode>
<xe:basicContainerNode label=”Apes”>
<xe:this.children>
<xe:pageTreeNode label=”Gorilla”
page=”/gorilla.xsp”>
</xe:pageTreeNode>
<xe:pageTreeNode label=”Chimp” page=”/chimp.xsp”></xe:pageTreeNode>
</xe:this.children>
</xe:basicContainerNode>
</xe:this.treeNodes>
</xe:navigator>

Here I do not have to define anything. The control will know itself when a selected node needs to be highlighted.

Gorilla XPage

In the app I have multiple XPages, in the gorilla xpage I have set the navigationPath property as follwed:

<?xml version=”1.0″ encoding=”UTF-8″?>
<xp:view xmlns:xp=”http://www.ibm.com/xsp/core&#8221;
xmlns:xc=”http://www.ibm.com/xsp/custom”&gt;

<xc:ccLayout navigationPath=”/Aap/Gorilla”>
<xp:this.facets>
<xp:image url=”/aap.jpg” id=”image1″ xp:key=”facet_1″></xp:image>
</xp:this.facets>
</xc:ccLayout></xp:view>

As a result the Aap titlebar Tab is highlighted:

titlebarTabs

Not really something that opens your mind but at least I have written it down (with a repo) in the hope I won’t have to re-learn it next time I have to use the application layout control.

 

 

 

Advertisements

Building a search function with DataTables plugin

Introduction

In Domino you have multiple options how to provide a search function for an application. I have seen many examples where a FT search query is build for a database, where the form type is defined, which fields should be used in the search etcetera. Most of them are a maintenaince nightmare, layout is little flexible and usability is lacking (e.g. perform a search towards a query which will result in zero hits).

What if you make it easier to maintain, more flexible for user specific desires and add facetted search principles? A win situation?

DataTables

In the following posts I will write how to use the jQuery DataTables plugin to provide a quick search function for your Domino apps. I assume you use XPages.

Stage 1 – Getting & presenting the data

In the initial stage we just try to get and present the data we need. As example I will be using the FakeNames application. I have created a public repo which has at the moment:

  • an xpage to present the data (dtPersons.xsp)
  • an xpage (api.xsp) which will contain rest services
  • a Java class that generates the data in JSON format
  • a CSJS library to transform the HTML table on dtPersons.xsp to  DataTables object
  • the required resources from DataTables.net
  • a Theme resource to have the resources available
  • a Notes view to use as data source.

In order to create some fake documents I have set up an LS agent to do so.

If you bind this all together, you have already a search function:

datatables01

Right on top you have a search field where you can query the columns in the table. The columns are sortable too. Probably it is matching most of the search functions you have seen for Domino. But wait! There is more possible…

 

JavaScript Internationalization & placeholders

Introduction

Some time ago I wrote about moving a Teamroom application up to IBM Bluemix. This month the XPages runtime is now general available.

In the post I mentioned I would come back on some design gotchas I saw while analyzing and preparing the Teamroom application for staging it to Bluemix. So here is (at least9 a first post.

What I noticed for example was the usage of the l18n library in SSJS and placeholders in properties files.

i18n formatting

This is a server script library with methods to format messages for localization, display dates in a locale-specific manner and miscellaneous Internationalization utilities.

So how does this works?

Create two or more strings properties file e.g.

  • strings.properties
  • strings_sv.properties

The strings.properties file content:

compliment=Handsome

hello.world=Hello {0}

The strings_sv.properties file content:

compliment=Snygging

hello.world=Hejsan {0}

Now create an XPage and place e.g. a Computed Field control on it and calculate it’s value:

<xp: text><xp: this.value><![CDATA[#{javascript:compliment = strings.getString(“compliment”);

return i18n.format(strings.getString(“hello.world”), compliment);}]]></xp: this.value></xp: text>

(Do not forget to enable Internationalization for your application in the Application Properties under section International Options)

Placeholders

Notice in the properties file the usage of a placeholder: hello.world=Hello {0} and how it is being referred: strings.getString(“hello.world”), compliment. Here the variable compliment (another string property value) is put in the placeholder.

As a result in the default language I get returned “Hello Handsome” and when I choose Swedish as default language in my browser I get returned “Hello Snygging”.

By wrapping it and formatting it with the L18n library you ensure it is fitted according the active language. This is very handy for dates, amounts etcetera.

Links of interest

More details about JavaScript Internationalization can be found in the IBM Notes Domino Application Development wiki.

 

Questions and Answers from deploying a Teamroom application on Bluemix

Introduction

write once, run everywhere

Thise WORE slogan is used often in cross-platform solutions, also in IBM Domino. But what if you move your XPages application from an on premise Domino installation to the cloud, more specific IBM Bluemix?

Teamroom

To gain some experience in this area I decided to take a well known application, IBM’s Teamroom and deploy it on Bluemix. I will spare you the details of creating a Bluemix account, setting up Domino Designer, deploying the Design application and binding it to a XPages NoSQL Database service. I will focus on adapting/preparing the Design of the XPages application and some areas I have not found an answer for (yet).

First consideration – Choose your data-binding

bluemixContext

Bluemix requires the separation of design and data so if you haven’t use this principle your applications yet, you must apply it now. Second, Bluemix will allow you also to run your XPages application in a mixed environment (part cloud / part on-premise) so if your application will do so the bluemixContext object will let you identify where your application is running and point to the corresponding data NSF.

DAO Bean

In my case the Teamroom application would only run in Bluemix so instead of applying bluemixContext.getDataService().findDatabaseName() I prefer to use Oliver Busse’s daobean which I have been using in other applications as well. This allows me to use the shorter dao.getDbpath() for xp:dominoDocument and xp:dominoView data-binding.

Remember: in the Teamroom design you need to set this property for every Document and View binding!

<xp:this.databaseName><![CDATA[#{javascript://bluemixContext.getDataService().findDatabaseName()
dao.getDbpath()}]]></xp:this.databaseName>

Use the search function in DDE to locate where these bindings are used.

Valuepickers

Value pickers are used throughout the Teamroom application and for the dataProvider property you need to calculate the location of the database.

Search after dataProvider and you will get the list of design elements where they are used. Look for the once who use the xe:dominoViewValuePicker since they are using a View as data-source. Again make the database location computed.

Addressbook

Some dataProviders use xe:dominoNABNamePicker and the location of the server is set via the Teamroom Setup function, which asks for the web server address. Default the web server address where the design resides is filled in. I tried to fill in the ip address of the server where the data resides (gathered via dao.getServer()) but this still did not allow me to open an NAB.

@dbcolumn @dblookup

What is an XPages application without the @dbcolumn and @dblookup functions? Use DDE to allocate in which design elements there are used and exchange the @DbName() function with bluemixContext.isRunningOnBluemix()? bluemixContext.getDataService().atDbName():@DbName or dao.getServer()+”!!”+dao.getDatabase()

database object

With the database object is you can make a quick reference to the NotesDatabse class, and so it is used throughout the Teamroom application. Mind a database.isFTIndexed() to check if the search bar will be displayed or not? Again do your search in DDE.

You can apply method chaining e.g. dao.getDatabase().isFTIndexed()

Run form validation

I noticed that I had to disable the option to validate the saving of documents using form validation (on document save option). Otherwise the operation failed silently.

Changing form name

Adding a team member via the browser resulted in a document created with the form reference of Team Member Profile   –   ParticipantProfile. If you add a member via the Notes client the form reference will be ParticipantProfile. This explains why newly created members did not appear in the list at first.

So I modified the form name as:
<xp:dominoDocument formName=”ParticipantProfile” …

I also set this alias as first in the Notes form. Not sure if that is necessary.

Wrap-up

So far so good. So how “Bluemix ready” is my Teamroom and what are my first thoughts?

Except the lookup to the name and address book I pressume my Teamroom is working as normal. I guess you can call this is major issue.

The tag cloud is not working, but that is due to the fact that the  xp:tagCoud control does not provide a database property (yet). Again I would call this a major issue.

Looking at the design of the Teamroom and counting the number of design elements I would think the development team has made the application design too complicated. I think the power of custom controls and property definitions is that you can re-use them in complete other ways and so reduce the amount of design elements.

I also notified almost no Java code in the design. Perhaps adding some classes for the objects can also reduce the amount of design elements dramatically. Also the application might get less spaghetti coded with logic stored in a central place.

Going through the code resulted in some new “discoveries” and was therefor fun to do. I will write another post about the things I haven’t used before.

Happy development and looking forward to next week’s Engage =)

 

 

Resource optimization for Anonymous users

The ‘Use runtime optimized … resources’ is a great XSP Properties property to downsize the amount of calls to the Domino server for downloading stylesheet and javascript resources.

In order to reduce the size of the download(s) the rendered property in a Theme design element can be handy.

For example resources that are used in Xpages that are not accessible by Anonymous users you can initially restrict via:

Screen Shot 2016-03-08 at 12.15.01

When they later logon and access XPages that use the resource, it will be available.

Just a simple tip. Happy development =)

Styling the Pager control for Bootstrap UI

Many of us are acquainted with  Bootstrap in our XPages application. However if you place a Pager control on your XPage it does not render according bootstrap style.

So what can you do?

If you have the option to install the Extension Library with Bootstrap in it: DO IT.

If you don’t have that option you can place the Bootstrap resources in your NSF or use a CDN.

If you are using these last two options you will notice the Pager control is still non-Bootstrap styled. You can either:

  • Apply CSS yourself (link, link)
  • Apply your renderer (link)

I noticed in the first approach the … display for page numbering will not be proper styled:

Screen Shot 2016-03-01 at 10.46.13.png

If you are a CSS-wizard you probably can fix this (I can’t).

The second approach renders the Pager perfectly with Bootstrap style applied and hopefully the strange behaviours Frank van der Linden refers to do not appear.

Happy development =)

 

 

Bootstrap Pills navigation for Dynamic Content control

Introduction

Besides parameters you can include a hash (#) property in the URL in your XPages application. This “fragment identifier” is a short string of characters that refers to a resource that is subordinate to another, primary resource.

So it is mainly used to set a location anchor to a part in a page.

In this post I will show how to get value of Hash property in XPages and make a nice Bootstrap Pills navigation control for the Dynamic Content Control

XPages

In XPages you can use it within the xp:link control but the dynamic content control also makes use of it.

XSnippet Dynamic Content Control

The following XSnippet demonstrates how to set up a dynamic content control:

<?xml version="1.0" encoding="UTF-8"?>
  <xp:link escape="true" text="Load Dynamic Content Server side" id="link1">
    <xp:eventHandler event="onclick" submit="true" refreshMode="partial">
      <xp:this.action>
        <![CDATA[#{javascript:getComponent("dynC").show("key1")}]]>
      </xp:this.action>
    </xp:eventHandler>
  </xp:link>
  <xp:link escape="true" text="Load Dynamic Content Client side" id="link2">
    <xp:eventHandler event="onclick" submit="false">
      <xp:this.script><![CDATA[XSP.showContent("#{id:dynC}","key2")]]></xp:this.script>
    </xp:eventHandler>
  </xp:link>
  <xe:dynamicContent id="dynC" useHash="true">
    <xp:this.facets>
      <xp:panel xp:key="key1">Content1</xp:panel>
      <xp:panel xp:key="key2">Content2</xp:panel>
    </xp:this.facets>
  </xe:dynamicContent>
</xp:view>
With this snippet you get the following Hash set in the URL of your XPage: #content=…

Getting value of Hash property

I suggest to use one of the following 2 options to collect the value of the hash property:

  1. Use a custom function
  2. Use Dojo

The first option is another XSnippet by Thomas Adrian. The second is a suggestion by Mark Leusink to (re)use Dojo.

getHashUrlVars

Include the function in a shared CSJS library and call it via the function getHashUrlVars()["content"].

dojo.queryToObject

The dojo approach is also straightforward. Call the function dojo.queryToObject( dojo.hash() ); and then abstract the content property var active = hash[“content”];.

Pills navigation for Dynamic Content Control

Since there is no list item control in XPages it is a bit hard to set the properties via computation. However via CSJS you can manipulate the DOM a lot and add some responsiveness yourself.

The following script builds an unorderlist containing links to set a part of the Dynamic Content control as visible:

<xp:div id=”nav-pills-container”>
<ul class=”nav nav-pills”>
<li id=”Pictures” class=”dclist”>
<xp:link escape=”true” text=”Pictures” id=”link4″>
<xp:eventHandler event=”onclick” submit=”true”
refreshMode=”partial”>
<xp:this.action>
<![CDATA[#{javascript:getComponent(“dynC”).show(“Pictures”)}]]>
</xp:this.action>
</xp:eventHandler>
</xp:link>
</li>

<li id=”Albums” class=”dclist”>
<xp:link escape=”true” text=”Albums” id=”link1″>
<xp:eventHandler event=”onclick” submit=”true”
refreshMode=”partial”>
<xp:this.action>
<![CDATA[#{javascript:getComponent(“dynC”).show(“Albums”)}]]>
</xp:this.action>
</xp:eventHandler>
</xp:link>
</li>
<li id=”Profiles” class=”dclist”>
<xp:link escape=”true” text=”Profiles” id=”link2″>
<xp:eventHandler event=”onclick” submit=”true”
refreshMode=”partial”>
<xp:this.action>
<![CDATA[#{javascript:getComponent(“dynC”).show(“Profiles”)}]]>
</xp:this.action>
</xp:eventHandler>
</xp:link>
</li>

</ul>

The second script checks which content section is set “visible” for the Dynamic Content control via the hash property in the URL. The corresponding list item in the Pills navigation is set as active.

<xp:eventHandler event=”onClientLoad” submit=”false”>
<xp:this.script><![CDATA[function setActive(id){
$( “li.dclist” ).removeClass( “active” );
var id = “#” + id;
$(id).addClass( “active” );
}

var hash = dojo.queryToObject( dojo.hash() );
var active = hash[“content”];
setActive(active);
]]></xp:this.script>
</xp:eventHandler>

As a result I get the correct list item displayed as active for my Pills navigation:

navpills

Code

In case you want to see the code working in an example download the Bildr application on OpenNTF. There I have applied this technique for the search function.

 

Re-Unite Gallery & FIX AMD loading for XPages

Introduction

In my previous post “Another draw (unite gallery) in the waste-basket” I wrote the complication I had with getting the Unite Gallery to work properly within XPages.

It turns out that this is related to Asynchronous module definition complications within XPages., although you do not get error messages in your web browser console.

Fixing the XPages R9 dojo define.amd problem once and for all

Marky Roden wrote a post about a solution a while ago which was inspired by a x-code snippet Ferry Kranenburg posted.

The principle is quiet simple but saves you a lot of headaches:

  • duplicates define.amd to define._amd
  • deletes define.amd
  • loads the AMD enabled jquery plugin (successfully)
  • duplicates define._amd back to define.amd
  • deletes define._amd

Using a Theme

In stead of setting the fix for individual pages I am using a Theme to fix it (since I am using a Select2 combobox in my navbar header).

amd fix

Step 1 – Adding two JS libraries to your WebContent

These files contain the same code as in the XSnippet.

Step 2 – Load your resources via a Theme design element

amd_theme

As you can see I load my JavaScript libraries who use AMD within the two previous set up libraries.

Result

As a result the buttons on the XPage containing the Unite Gallery work fine again !

Happy development =)

 

Another draw (unite gallery) in the waste-basket

Gallery galore

For an application I want to provide an image slider, in stead of the default Bootstrap carousel. I remembered a blog post of Johnny Oldenburger about Unite Gallery a while ago so I gave that a try.

Repeat and xp:image

Where Johnny demonstrated some static images I want to populate the image collection so I set up a repeat control with an xp:image control inside and calculate it’s properties.

Here is what the code looks like:

Code

The code of the XPage you can download here.

 

Code walk-through

After loading the JS resources I have a script block that build the gallery when the document is ready. The div gallery functions as container for the gallery.

Then I have a repeat control. An album object is just a Notes document that contains references to other Notes documents containing the picture files. So my Album.getPictures method returns a vector of references for which I have to make a lookup (via a Picture object) and collect some values (which size picture to use (thumbnail or original).

I separate the design from the data, so I also have to collect the location of the data db.

In the example I have two ways to define the image, one is via a xp:text control and the other is via the xp:image control. I rather prefer this last option.

Result

 

Below you can see a snippet of how the result. At first it looks nice, does’t it?unitegallery

Complications with XPages

So after I got the gallery on my XPage with dynamic content I started to notice undesired behaviour. My Bootstrap navbar links (xp:link) didn’t work anymore. Buttons on the same page stopped behaving and more.

A quick search after “Unite Gallery and XPages” lead me to some stackoverflow questions where people described similar problems.

Untill now I have not found a solution to get it working.

Lesson learned

Before implementing a plugin in XPages, do some research on possible complications.

 

 

Quick way to get dynamic (BS) list groups from Notes views

Introduction

For an app I needed lists to let users quickly to have access to a subset of documents. Bootstrap has a nice feature called List Groups which gives you a nice basic UI for unordered lists with list-items.

A list group can contain badges which I find a nice alternative for a tag cloud which to me are not very mobile friendly.

Before we get started let’s show how the end-result could look like:

list-group computed

So how do we do this in XPages & Java?

First I want to point to a snippet Oliver Busse posted about Iterating through a HashMap in a repeat control. If you use that basic principle of binding a HashMap to a Repeat Control  and use a categorized view for filling the Hashmap you are there!

Java class snippet

Below is the snippet from my Java class:

public Set<Entry<String, Integer>> categoriesMap(String viewName) throws NotesException{
HashMap<String, Integer> categories = new HashMap<String, Integer>();
Database dataDB = dao.getDatabase();
String ViewName = viewName;
ViewNavigator nav = dataDB.getView(viewName).createViewNav();
ViewEntry entry = nav.getFirst();
while (entry != null && !entry.isTotal()){
categories.put(entry.getColumnValues().firstElement().toString(), entry.getChildCount());
ViewEntry tmpentry = nav.getNextSibling(entry);
entry.recycle();
entry = tmpentry;
}
nav.recycle();
return categories.entrySet();
}

The code will run through the provided Notes view and go through the categories and places the name/label and value/totals in a Map and returns a set view of the mappings contained in this map.

Custom Control

Next step is to place the list-group code from Bootstrap in a custom control and make it dynamic by generating the list-items via a Repeat control and bind that control to my Java code:

<?xml version=”1.0″ encoding=”UTF-8″?>
<xp:view xmlns:xp=”http://www.ibm.com/xsp/core”&gt;
<h2>
<xp:text
escape=”true”
id=”computedField1″
value=”#{javascript:compositeData.header}”>
</xp:text></h2>
<ul class=”list-group”>
<xp:repeat
id=”repeat1″
rows=”30″
var=”obj”
indexVar=”idx”>
<xp:this.value><![CDATA[#{javascript:var viewName = compositeData.viewName;
Picture.categoriesMap(viewName);}]]></xp:this.value>
<li class=”list-group-item”>
<span class=”badge”>
<xp:text
escape=”true”
id=”computedField2″
value=”#{javascript:obj.getValue()}”>
</xp:text>
</span>
<xp:link
escape=”true”
text=”#{javascript:obj.getKey()}”
id=”link1″>
<xp:eventHandler
event=”onclick”
submit=”true”
refreshMode=”complete”>
<xp:this.action>
<xp:openPage>
<xp:this.name><![CDATA[#{javascript:var target = compositeData.targetPage;
return target + “?filter=” + obj.getKey();}]]></xp:this.name>
</xp:openPage>
</xp:this.action></xp:eventHandler>
</xp:link>
</li>
</xp:repeat>
</ul>
</xp:view>

Properties

The custom controls takes in some properties set in the Property Definition section. Via this way I can re-use the Custom control for multiple dynamic list groups:

Conclusion

As you see, with a minimal amount of code you can create dynamic lists for your apps. In the sample above I do not handle views with more than 30 categories but I am sure you fix this yourself. Also the active class property is not implemented.

Happy development =)