Posts Tagged: ‘Parameter’

XPages: JQuery Gantt Module

16. September 2012 Posted by airwolf89

In the past weeks I was trying something new, at least new for me…

I realised that using jQuery in Xpages is a wonderful idea. Mark Roden has a nice blog with great things you can do with jQuery in XPages. You can find it here: Xomino Also check out his demo site: Xomino JQinX Demo

In one project I wanted to use a gantt chart. I want to write this article to show you how it’s done and warn you about the problems I had.

Let’s start.

To use jQuery you have to download it and integrate it in your database. Build your own version of jQuery here: JQuery Download It is the download page of JQuery UI, a set of many nice plugins and modules for jQuery. A version of the base jQuery is included. You can also configure a custom theme for your jQuery modules. It is on the right menu when you follow the link “design a custom theme

For the gantt chart I am using this module: Taitems JQuery Gantt Chart Module

So, now you have to integrate these files into your database. You can do this either via the resource category in the database, or via the PackageExplorer (it is an Eclipse View) I recommend using the package explorer, because you can manage your files more easily. Simply drag and drop your files and create some folders to organize them.

Now you have to load them into your application. You can do this easily via a theme with the following statement:

<resource>
<content-type>application/x-javascript</content-type>
<href>js/jquery-1.7.min.js</href>
</resource>

Or you load them directly into your code via the resource properties of the XPage/ Custom Control

<xp:script src="js/jquery-ui-1.8.23.custom.min.js" clientSide="true"/>

You have to do this for the jQuery base module, the UI module and the gantt module, also you have to load the CSS files.

First problem I had to face: The gantt module doesn’t work with every jQuery version. I was using jQuery 1.8.0. But when using this module, I had an error message which complained about some undefined variables (TypeError: m is undefined) Using the 1.7 version was a solution to this.

Now we can get started. On the page of the gantt module is an easy manual how to use this module. It is quite self explaining.

To implement a gantt chart, you only have to put in these few lines of code (client side of course)

<xp:scriptBlock id="scriptBlock1">
<xp:this.value>
// + "/ganttJSONBuilder?OpenAgent";
// + "/js/data.js";
jQuery( function() {
var dataPath = location.href.substring(0,
location.href.lastIndexOf('/') + 1)
+ "/ganttJSONBuilder?OpenAgent;

$(".gantt").gantt( {
source : dataPath
});
});]]>
<<!--xp:this.value>
<<!--xp:scriptBlock>

As data source the module uses JSON data. Use this site to validate your JSON data easily. The structure of your data is explained in the manual site of the module.

Be aware, the module expects a URL as data source. That means you can’t use server side Javascript in that scriptblock to generate the data source. So, we have two options on how to load the data into the module, either via a file which you can put into the WebContent folder in your database, or you call an agent. The agent is probably the better option because you sure want to load data dynamically.

Using an agent to achieve this is basically easy, you only have to write your JSON string into a variable and then you do this:

PrintWriter pw = getAgentOutput();
pw.println(output);

The difficulty of generating the JSON string itself depends on your data. In my case it was a simple project management, so some tasks, projects and editors. I used a view. I looped the entries and parsed the information into a JSON String.

There are some nice little things you should know when doing so.

The first line of your JSON string has to be the content type of the output, for JSON it is: Content-type: application/json; charset=utf-8\n
Also, it is very important that you use line breaks in the string, simply by using \n. If you aren’t doing that, your JSON string will not be properly interpreted and the module shows nothing but a nice grey bar.
Easily to overlook, but also important, in JSON you have to use a comma to separate your entries. Be sure you have no comma behind your last entry or parameter. It will result in a misinterpretion of the data.
The next important thing is, in the JSON data, you have to provide all entries defined in the manual. That means, if you forgot to write one of the parameters into the string, it is valid, but not recognized by the gantt module and isn’t doing anything. All of them need a value. providing nothing will have the same result: Nothing =)
I wanted to have my projects and tasks separated. In one line the project and then in the other lines the related tasks. This is possible by writing an extra entry to your JSON string, in which you only write the information about the project. When writing the tasks of the project, you probably don’t want to write the project in front of each task. If you think you can define an empty string for the name parameter of the JSON entry, you are wrong. The module needs a value of at least one character. Using an empty string results in not displaying the chart and some nice error messages. Using a space (” “) is the solution.
Also, you have to provide a start and end date for each entry. I wanted to have no duration for the project, so I didn’t provide the “from” and “to” parameter, it rewarded me with some other javascript errors. So I used the whole duration of the project for the project entry, it’s a good feature anyway.

A nice feature: You can use HTML in your JSON parameters, so, if you use
tags for example in your desc parameter and some formatting tags, you can make the mouseOver of the entries look more beautiful and put some more information into it.

If you think the styleClasses available for your entries in the chart (ganttRed, ganttGreen, ganttOrange) are not that beautiful, or you want to use some more, you can easily define some. There is a css file in the module. Looks like this:

.fn-gantt .ganttOrange {
background-color: #FCD29A;
}
.fn-gantt .ganttOrange .fn-label {
color: #714715 !important;
}

Copy those entries and do your own styles, the class at the end of the definition is recognized by the module, so you can use it directly in the “customClass” parameter of your JSON.

But there is one big problem when using this module. Above the chart, I have some buttons. I wanted to load different charts with those buttons. Easily done I thought, just firing a partial execute on the chart container to set another data source or something. But, nothing happens, in fact really nothing, not even an event which I could see in my FireBug. Some other buttons with only clientside code are working fine. All other buttons on the whole page are working fine, only those I have directly above my chart didn’t wanted to work. I haven’t figured out what’s the problem, if I find it, I will let you know.

Another problem is that the gantt chart is not working in the Notes Client. If I open the Xpage in my Notes client, the chart isn’t loaded, only a nice grey bar. Other jQuery modules are working fine, for example the accordion or flip is working, but not the module. If you want to use it in the NotesClient you should think about another solution… or wait until I find a solution for this problem =)

Another thing you should consider are loading times. The loading time is increasing dramatically proportional on how many entries you display (rowsPerPage parameter in the gantt function) and how many years they cover. If you want to display some tasks from a period of 10 years or more, you have to wait a bit. I tried a period of 30 years… not a good idea, my browser crashed… after about 5 minutes of loading.

So, I think that’s all I know about the module and how to use it. Despite all the small and big problems I have a nice application with some really nice gantt charts. If you are interested in such an application, you should visit this page (Cobalt Software GmbH), the new version should be available soon. Ok, sorry for the advertisement…

If you have any questions or solutions for my unsolved problems, the comment section is all yours =)

Hope it was useful for some of you.


Filed under: Notes & XPages Tagged: Chart, Cobalt Software GmbH, CSS, Datasource, Gantt, Javascript, JQuery, JSON, Mark Roden, Notes, Parameter, Plugin, Serverside Javascript, Taitem, Tools, Xomino, XPages, Xpages in NotesClient, XpInc

XPages: Notes Objekte in Java Singleton Patterns

28. März 2012 Posted by airwolf89

Ich hatte ja vor einer Weile in diesem Post am Ende von einem Problem berichtet, welches ich im XPages Forum gepostet habe.

Gestern habe ich mit Philippe Riand, dem Chef-Entwickler der XPages von IBM, über das Problem gesprochen. Hier ist die Erklärung:

Ich habe ja das NoteDatabase Objekt in der Klasseninstanz als Attribut gespeichert. D.h. dass bei jedem Request das gleiche Objekt verwendet wird, wie es ja auch bei einem Singleton Pattern sein soll.
Aber: Nach jedem Request wird ein NotesDatabase Objekt recycled, und zwar schon seit 8.5.1. Das hat einfach den Hintergrund, dass in dem NotesDatabase Objekt die Credentials des Users, der den Request abgeschickt hat, mitgespeichert werden. So würde, wenn User A die Funktion aufruft und die Klasse initialisiert, und dann User B die gleiche Funktion aufruft, die gleiche Instanz verwenden, in dem das NotesDatabase von User gespeichert ist. Würde somit die Funktion mit den Berechtigungen von User A aufrufen. Das darf natürlich nicht passieren. Daher wird, schon seit 8.5.1, ein NotesDatabase Objekt nach jedem Request recycled. Da das ganze in dem Singleton Pattern abläuft ist natürlich das Objekt noch da und nicht Null, hat aber keine Referenz mehr zur eigentlichen Datenbank und wirft somit den Fehler dass das Objekt removed oder recycled wurde.

Macht von dem Gesichtspunkt her natürlich auf jeden Fall Sinn, man muss es halt nur wissen.

Natürlich ist die Frage warum es dann bei mir unter 8.5.1 funktioniert hat. Die einzige Erklärung die wir finden konnten war, dass dies ein Bug unter 8.5.1 sein muss. Das sollte man denke ich auf jeden Fall mal bei sich in den Anwendungen überprüfen, da dies theoretisch ein ziemliches Sicherheitsrisiko sein kann.

Stattdessen sollte man, z.B. beim Aufruf der getInstance Methode die aktuelle Datenbank übergeben oder sich in der Java Klasse das Objekt direkt holen und jedes Mal neu setzen.


Einsortiert unter:Notes & XPages Tagged: Attribute, credentials, Error, ibm, Java, Notes, NotesDatabase, Parameter, Phillipe Riand, Referenz, removed or recycled, Request, Serverside Javascript, Session, Singleton Pattern, XPages

XPages: Useability – Parameter mit Aliaswerten in Custom Controls

15. November 2011 Posted by airwolf89

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: Tippsammlung

18. Oktober 2011 Posted by airwolf89

Hallo,

hier mal eine kleine Ansammlung von Tipps welche meine Kollegen und ich uns im Laufe der Zeit notiert haben.

Attributbenennung im IE

Dojo scheint bei Attributselektoren (z.B. dojo.query()) im Internet Explorer Probleme zu haben, die richtigen Elemente zu finden, wenn ein Teilstring des Attributs ein reserviertes Wort (z.B. name oder id) enthält. Da Dojo wie jQuery als Selektor-Engine Sizzle einsetzt, kann dieses Phänomen auch bei jQuery auftreten!

Beispiel hierfür ist ein Input-Feld mit dem Namen „username“. Selektiert man dojo.query(‘input[id$="WFApprovalVFL"]‘) wird das username-Feld mitselektiert, obwohl es nicht auf WFApprovalVFL endet.

Selbiges gilt für Keynamen in JSON-Objekten.

Nich gerenderte Datasources werden dennoch computed

Wenn man in einem Custom Control eine Datasource verwendet, dann wird dessen Code IMMER ausgeführt, egal ob rendered=“false“ oder loaded=“false“. Der Code dazu wird immer ausgeführt. Dies kann zu schwer nachvollziehbaren Fehlern führen.

Des weiteren, wenn man mehrere Datasources in unterschiedlichen Custom Controls hat, welche auf das selbe Dokument zeigen, so werden alle diese Datasources gespeichert und ggf. mehrere Dokumente desselben Typs angelegt.
Um dieses Problem zu umgehen kann man in den Custom Controls entweder die Datasource auf der XPage direkt über den namen referenzieren, oder man übergibt die Datasource per Parameter an das Custom Control (compositeData). Da muss man allerdings manuell einen Typ auswählen, da Datasources nicht in der Liste auftauchen. Der Typ heißt: com.ibm.xsp.model.ModelDataSource

Prüfen ob ein Viewpanel kategorisiert ist

Gesetzt den Fall, das zu prüfende View Control auf der XPage heißt viewPanel1, liefert:

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

den Wert 0, wenn die View kategorisiert ist, -1 wenn nicht.

Use case: Bei kategorisierten Views gehen die Inhalte der Kategoriespalte verloren, wenn die View umsortiert wird. Hiermit kann man prüfen, ob die View umsortiert ist und entsprechend die Anzeige wiederherstellen.

Umgehen des OnChange-Bugs im IE beim Klick auf eine CheckBoxGroup

Werden auf einer XPage oder Custom Control Radiobutton Groups oder Checkbox Groups verwendet, tritt im IE das Phänomen auf, dass beim Partial refresh die übergebenen Werte der Gruppe immer die Werte des vorangegangenen Requests sind. Dies tritt nur auf, wenn man auf das Label klickt, statt direkt auf die Box zu klicken. Grund hierfür ist, dass der IE den Partial refresh-Request abschickt, bevor auf der UI der neue Wert gesetzt wird.

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


Beispiel
:

Es gibt eine Checkbox-Gruppe mit den Optionen A, B, C, D. Beim onchange-Event wird ein Partial refresh auf ein anderes Panel ausgelöst, das abhängig von den gewählten Optionen Elemente ein- oder ausblendet. Klickt man auf das Label für die Option A, kommt kein gewählter Wert an. Klickt man anschließend auf das Label für die Option B, kommt der Wert A an. Klickt man anschließend auf das Label der Option C, kommen A und B an, usw.


Workaround
:

Im onclick-Eventhandler wird der Partial refresh beim oncomplete ein zweites Mal ausgeführt.

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

Obiger Workaround 1 wirkt nicht, wenn auf dem Eventhandler zusätzlich noch Aktionen bzw. Server Side Javascript ausgeführt werden soll. Dieser Code wird dann nur beim ersten partial refresh ausgeführt. Um diesen Eventhandler wieder gängig zu machen, muss man den Click-Event des Labels von seiner Standard-Aktion abhängen und selbst durchführen. Dies macht man in einem clientseitigen Scriptblock. Da aber die Checkbox selbst auch innerhalb des Labels liegt, muss man diese wiederum aus der eigenen Verarbeitung rausnehmen:

 <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>

Ein weiterer Vorteil dieser Methode gegenüber Workaround 1 ist, dass kein zweiter Request nötig ist.

Validierung von zwei abhängigen Eingabefeldern

Bei der Validierung von zwei voneinander abhängigen Eingabefeldern muss der SubmittedValue des Feldes abgefragt werden, das validiert wird. Vergleicht man den Value des Feldes mit dem Value des zweiten Feldes, wird die Validierung nach dem ersten Fehlschlag nicht mehr ausgelöst und der Validierungsfehler bleibt bestehen.

Beispiel:

 <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>