Social Icons

twitterfacebookgoogle pluslinkedinrss feedemail

Pages

Featured Posts

My little contribution to the Lotus Community

This blog is my attempt to help other domino developers by sharing some of my coding experiences

My little contribution to the Lotus Community

This blog is my attempt to help other domino developers by sharing some of my coding experiences

Sunday, October 21, 2012

Choosing between xpages controls and plain html elements

It is better to use plain HTML elements as far as possible inside your xpages/custom control markup. For example, if you don't need to do a partial refresh of a DIV or you don't need to work with that DIV on the server side at all, you better use the plain div instead of the xp:div. The same is true with any other html elements. This will reduce the number of component objects the JSF tree has to maintain on the server and understandably will improve the performance. (Before JSF 1.2 it was not recommended to mix in JSF and plain html tags)

Having said that, how do you know if a div is going to be accessed on the server side right when you design the page!! What I do is to start with plain html elements for which it is less likely to have an associated server side code (like partial refresh/onclick event) and then convert it to a xpages tag later when I discover it needs some server side handling.

There are some instances where you need to do some server side computing while rendering the plain html code to the browser. For instance, if I need to render a plain html div tag (because I don't have any server side code attached to it) with some attributes computed based on some business logic. You can do something like the following.

 div class="row" me="customer" myid="#{javascript:entryCustomer.getKey()}" parid="#{javascript:entryCompany.getKey()}">  
   <!-- some other controls or contents go here -->  
 </div>  

I am sure I tried something like this in version 8.5.1 and it didn't like it. Since then I was thinking that a server side evaluation won't work other than on a standard xpage control. Just out of curiosity I tried it today, and it works. Very cool, now I can replace a lot of xpages controls with plain html controls.

Tuesday, September 18, 2012

XPages – Checkbox loses it’s checked state when partial refresh is triggered by the click event of the checkbox

When XPage renders the checkbox group control, it generates the label tag for the options text. So the users do not need to target the tiny boxes to make selection, rather they can click on the label to select the option. This also helps with the screen readers. The following is a sample html generated by XPage.
<fieldset class="xspCheckBox" id="view:_id1:checkBoxGroup1">
<table class="xspCheckBox">
<tbody><tr>
<td>
<label><input type="checkbox" value="one" name="view:_id1:checkBoxGroup1">test1</label></td>
<td>
<label><input type="checkbox" value="two" name="view:_id1:checkBoxGroup1">test2</label></td>
<td>
<label><input type="checkbox" value="three" name="view:_id1:checkBoxGroup1">test3</label></td>
</tr>
</tbody>
</table>
</fieldset>
I am working on a page where I need to filter a view based on the options selected in a checkbox group. I am doing a partial refresh on the onclick event of the checkbox (onChange event won’t work cross-browser). What I noticed is, when the label of a check box option is clicked to make a selection (as opposed to clicking the box), the checked status of the option is not submitted to the server. If you don’t believe, then try the following code.
<xp:checkBoxGroup id="checkBoxGroup1" immediate="true">
    <xp:selectItem itemLabel="test1" itemValue="one"></xp:selectItem>
    <xp:selectItem itemLabel="test2" itemValue="two"></xp:selectItem>
    <xp:selectItem itemLabel="test3" itemValue="three"></xp:selectItem>
    <xp:eventHandler event="onclick" submit="true"
        refreshMode="complete" execMode="partial" execId="checkBoxGroup1">
        <xp:this.action><![CDATA[#{javascript:print("sel vals:"+getComponent("checkBoxGroup1").getSelectedValues());}]]></xp:this.action>
    </xp:eventHandler>
</xp:checkBoxGroup>
After a little research, I figured that the moment the label is clicked, the partial refresh is getting fired. Meaning, the browser toggles the checkbox option only just after the partial refresh is fired. The work around I came up with is: When the user is clicking the label of the checkbox option, stop the event and call the click of the associated box. Just 3 lines of code and it works perfect on all browsers.
<xp:checkBoxGroup id="checkBoxGroup1" immediate="true">
    <xp:selectItem itemLabel="test1" itemValue="one"></xp:selectItem>
    <xp:selectItem itemLabel="test2" itemValue="two"></xp:selectItem>
    <xp:selectItem itemLabel="test3" itemValue="three"></xp:selectItem>
        <xp:eventHandler event="onclick" submit="true"
            refreshMode="complete" execMode="partial" execId="checkBoxGroup1">
            <xp:this.action><![CDATA[#{javascript:print("selected values:"+getComponent("checkBoxGroup1").getSelectedValues());}]]></xp:this.action>
            <xp:this.script><![CDATA[if (thisEvent.target.tagName.toLowerCase()=="label") {
    dojo.stopEvent(thisEvent);
    thisEvent.target.childNodes[0].click();
}]]></xp:this.script>
        </xp:eventHandler>
</xp:checkBoxGroup>
If there is a better way to fix this little bug, please let me know.

Tuesday, June 26, 2012

NotesException: Entry is no longer in view

If you have a view that has documents listed multiple times (Show multiple values as separate entries checked in the view column) and that view is used in code like shown below, there are high chances that you will get the run time error NotesException: Entry is no longer in view: <ViewName>


ViewEntryCollection vec=vwUsers.getAllEntriesByKey(keyLkp,true);
if (vec.getCount()==0) return null;
ViewEntry veTemp;
ViewEntry ve=vec.getFirstEntry();
while (ve!=null) {
      System.out.println("ve.getUniversalID():"+ve.getUniversalID());
      veTemp=vec.getNextEntry(ve);
      ve.recycle();
      ve=veTemp;
}


Apparently this issue has been reported to IBM back in 1999. So I am thinking there is no fix to this issue yet. Here is a simple work around.


ViewNavigator vnavUsers=vwUsers.createViewNavFromCategory(keyLkp);
if (vnavUsers.getCount()==0) return null;
ViewEntry veTemp;
ViewEntry ve=vnavUsers.getFirst();
while (ve!=null) {
      System.out.println("ve.getUniversalID():"+ve.getUniversalID());
      veTemp=vnavUsers.getNext();
      ve.recycle();
      ve=veTemp;
}


This solution is discussed in the notes.net couple of times. Thanks to Sam Bridegroom for suggesting this solution.

Wednesday, February 29, 2012

Eclipse: Compare with \ Each Other or Local History…


There were several posts about how to compare different versions of your code (Xpages/Custom Control) available in the local history.

But I don't remember seeing anything about comparing 2 different files (Xpages/Custom Controls/Script Libraries/Style Sheets/ any text file) within the same database or different databases in the notes community forums.

Suppose something went wrong when you modified the code, but you have it working in an earlier version of your code. If you have a backup of the working version of your database, you can compare the file that you suspect has the buggy code in it with the backup version of it.

All you have to do is, switch to the java perspective (or open the package explorer view), select the 2 files that you want to compare using the ctrl key while selecting, and right click\Compare with\Each Other…

Tuesday, October 25, 2011

XPages: sessionAsSigner & sessionAsSignerWithFullAccess mix-up (Xpages BUG??)

I spent around 3 days chasing a [TypeError] exception while trying to delete a document. According to the IBM documentation, sessionAsSigner works with the effective (web) access of the Xpage signer.

If my basics are not wrong, a User with Editor access should be able to delete a document even if that person's name or role or group is not in one of the authors field of the document. I logged in as me (I myself is the signer too, no other developer is working in my database) and tried to delete a document with the sessionAsSigner access. It didn't let me delete (You are not listed as one of the authors error). I have Manager access in the ACL and the "Maximum internet name & password" settings was Editor.

According to the IBM documentation, sessionAsSignerWithFullAccess should give admin access to the data (So it seems like the sessionAsSigner is not applicable to the "documents" in which case the above behavior is correct).

So I used the sessionAsSignerWithFullAccess to get the database object. Still no luck on deleting the document (same not authorized error). After a lot of trial and error, it appears to me that it is a mix-up issue between sessionAsSigner and sessionAsSignerWithFullAccess.

Here is the code for reference (the replica ids are fake)

function removeDocument() {
      var dbA=sessionAsSigner.getDatabase("","");
      dbA.openByReplicaID(@DbName()[0],"85XXXXE2005BXXXX");      
                 
      var dbB=sessionAsSignerWithFullAccess.getDatabase("","");
      dbB.openByReplicaID(@DbName()[0],"85YYYY500046YYYY");

      var vw=dbB.getView("($All)");
      var doc=vw.getFirstDocument();
      doc.remove(true);
}

If a previous code is getting a sessionAsSigner, then a subsequent attempt to access the sessionAsSignerWithFullAccess gives only a sessionAsSigner level of access.

If I change the first line of code to get the dbA from session (instead of sessionAsSigner), then the sessionAsSignerWithFullAccess on line 3 gets the full access as expected.

Has anyone faced this issue before?? I am thinking that it is a bug on the implementation of this feature. This issue was there on 8.5.2 also (We recently upgraded to 8.5.3).

The sessionAsSigner need not be in the same script to reproduce this issue. If anywhere else in the code, a sessionAsSigner is accessed before calling the delete code, the same issue happens.

Tuesday, March 15, 2011

XPages - Difference between xp:this.data (xp:dominoView) and xp:dataContext usage?

One of the useful thing I learnt at a quick glance over the book ("Mastering XPages") so far is the dataContext. In fact, I was thinking how can some complex computation be done in one place in the XPage and then reference that computed object anywhere else in the page. dataContext is just what I needed.

Now that I use it extensively in my code, I kind of started thinking that the xp:this.data is also almost like a dataContext. (I may be totally wrong, but then I need someone to tell me that). And I had to use the xp:dominoView and a dataContext variable as the value of a repeat control conditionally. You might be wondering, what made me think to do something like that. Here is the story.

I have built a re-usable custom control (using xp:dominoView as the repeat control value) and I needed to implement a search inside the single category. I know that the search will just ignore the “categoryFilter” or the “keys”. Then the only way for me is to add the single category as a part of the view search query. Unfortunately, the single category column is complex and it is hard to come up with a generalized search syntax.

That’s when I thought of using a dataContext like the following as the repeat control value when the search is on.


            <xp:dataContext var="dcSearchResults">
                  <xp:this.value><![CDATA[#{javascript:var db:NotesDatabase=session.getDatabase("","")
db.openByReplicaID(sServerName, sReplicaID );
var vw=db.getView("view1");
var dc=vw.getAllDocumentsByKey("key1");
return dc.FTSearch("some query"); /*Code not tested*/
}]]></xp:this.value>
            </xp:dataContext>
</xp:this.dataContexts>

The dominoView is defined like the following.

  
      <xp:this.data>
            <xp:dominoView var="dominoView"
                  categoryFilter="#{javascript:compositeData.SingleCategory}"
                  databaseName="#{javascript:compositeData.Database}"
                  viewName="#{javascript:compositeData.ViewName}">
            </xp:dominoView>
      </xp:this.data>


The repeat control value was originally the following.


      <xp:repeat var="ViewEntry" disableTheme="true" id="rptViewBody"
                  value="#{dominoView}">


The value is modified as the following so that depending on if the search is on/off, the repeat control will get a different array to loop through. The search result rows displayed correctly when search was on, but as feared the dominoView didn’t display any rows when search was off.


      <xp:repeat var="ViewEntry" disableTheme="true" id="rptViewBody"
                  value="#{javascript:isSearchOn()!=true?dominoView:dcSearchResults}">


So, it appears that the xp:dominoView cannot be mixed with other code like a dataContext. It has to be a simple “#{dominoView}” or “#{javascript:dominoView}” (dominoView is the name of the variable).

Or am I missing something here? (I have posted this question on the xpages forum too.)

Monday, March 14, 2011

XPages Partial Refresh: Some day you will run into this nasty javascript issue with Internet Explorer.

I usually keep the client ids of the controls in a global JavaScript variable (JSON Object) so that they can be referenced in the client side JavaScript functions easily. Recently I did a dijit.Dialog popup from a XPage that worked just fine in Firefox (as always). Hoping that it should also work in the Internet Explorer, I did a test and not so surprisingly, the dialog didn't show up as a dialog.

I took a copy of the database before I start messing with the code during my debugging exercise. And later, I figured out that the javascript code in the partial refreshed custom control didn’t fire as expected. Also, it turned out that the global object I defined in the cc is showing as undefined in the debugger tool.

I did some research and found the following blog that nicely listed few different scenarios where IE breaks the JavaScript.

http://ragrawal.wordpress.com/2007/10/25/top-5-reasons-why-ie7-is-complaining-about-your-javascript/

I had already faced the 2nd scenario (Comma issue), so that isn't this time. But my bad, I didn’t declare my variable with the “var” keyword. Fixed it, and did a testing, still the JavaScript code didn’t fire.

Then I noticed that the script block is almost at the top of the custom control preceded by the dataContext and data tags. So that means, the html output has the <script> as the first tag which is the first scenario listed in the above mentioned blog.

I put a div just above the script block and then the JavaScript started working. Have I not come across that blog, I would have gone with some work around without really understanding the cause.

Here is the code that I put in the custom control immediately after the xp:view tag.


 <div style="display:none">-IE Hack-</div>