Wednesday, January 13, 2016

Reversing the display order of a Multi-value field (XPages)

Today I needed to reverse the display of a multi-value field. It's a log of actions and we needed to show the most recent on top rather then the first added. JavaScript arrays have a reverse() function but when I took the vector I got back it was coming in as an object not an array. I didn't want to spend more time on it, so I decided to reverse the elements in the vector.  I'm showing the results in a repeat.

So what I decided to do was reverse the vector. Below is my code to do it. It takes one vector and puts all the elements into a new vector and returns that:

  var iVector = new java.util.Vector();
    iVector = SSJSgetItemValueSet(doc, "lastresult", iVector);
    var oVector = new java.util.Vector();
    for(var nV=(iVector.size()-1); nV >= 0; nV--){
        oVector.addElement(iVector.elementAt(nV));
    } 

return oVector;
 
SSJSgetItemValueSet is a function I have in a library to assure that I get a vector from a NotesItem. Here is that function:

   function SSJSgetItemValueSet(iDoc:NotesDocument, iItemName:String, iVector:java.util.Vector) {
    //this is designed to see if there is any value in the field, and if so, to get all of it.
    //if there is only one value, still put it in a vector
    //if null, put null in as the value
    //java.util.Vector.size() is the # of elements in the vector
    //call as: iVector = SSJSgetItemValueSet(nDoc, approvedField, iVector);
    //this overloaded method is for when we want to do this from an XPage, and we can't pass a Notes object (like a Doc) into a bean,
    iVector = null; // always set to null
        try {
            if (iDoc.hasItem(iItemName)) {               
                var iItem:NotesItem = iDoc.getFirstItem(iItemName);
                var passObj = getValueAsVector(iItem.getValues());
                iVector = passObj;
            } else {
                iVector = null;
            }
        } catch (e) {
            e.toString();
        }   
    return iVector;
}
Hopefully this will be useful for someone.

Cheers,
Brian


Monday, December 7, 2015

nhttp preview won't "switch ID"

With XPages I use the nhttp preview a lot. Today I wrapped up work using one ID and switched to another one. I had made a simple change and was checking on it and it wouldn't load. The error was that it couldn't open a database - both were on my local, and working for months. It turns out that the nhttp preview was the problem. I shut it down and relaunched the clients and it worked.

I wonder if nhttp has a reload command...

Cheers,
Brian

Wednesday, November 4, 2015

DirectoryNavigator via Java

So looking into something, I discovered there has been an addition called a "DirectoryNavigator", it's supposed to make it easier to get to person docs in the NAB. I needed something like this, but in Java - the examples are in LotusScript, and I'm working in a bean. Those examples are "TBD". I did get it working, so I'm sharing. It looks like this came out in R8.

What you do is create a vector with the field names you want to retrieve, and you create a vector with what you want to look up (names). You check to see if there is a match, and if so, iterate through the resultset and get the items retrieved. Here is a snippet of the code (dir is the NAB):

            Vector<String> itV = new Vector<String>();
            itV.addElement("ShortName");
            itV.addElement("HTTPPassword");
            itV.addElement("FullName");

            Vector<String> nameV = new Vector<String>();
            nameV.addElement("Smith");

            System.out.println("before dirNav");
            // DirectoryNavigator dirNav = dir.l
            DirectoryNavigator dirNav = dir.lookupNames("$Users", nameV, itV, true);

            while (dirNav.isMatchLocated()) {
                System.out.println("found");
                // dirNav.findFirstName();
                System.out.println("The first value is: " + dirNav.getFirstItemValue());
                for (int i = 0; i < 5; i++) {
                    try {
                        System.out.println("Next value is: " + dirNav.getNextItemValue());
                    } catch (Exception divE) {
                        System.out.println("in catch");

                    }
                }
                dirNav.findNextMatch();
            }

 
Here is the print results. I've obscured the names, but we get the hierarchical names, and the common names.

10/28/2015 08:45:00 AM  HTTP JVM: starting
10/28/2015 08:45:00 AM  HTTP JVM: new start
10/28/2015 08:45:00 AM  HTTP JVM: before dirNav
10/28/2015 08:45:00 AM  HTTP JVM: found
10/28/2015 08:45:00 AM  HTTP JVM: The first value is: [lsmith]
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: [(390ACEC884A01BFDF5FA36AE5E6B29B1)]
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: [CN=RRRRRRRRR]
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: []
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: []
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: []
10/28/2015 08:45:00 AM  HTTP JVM: found
10/28/2015 08:45:00 AM  HTTP JVM: The first value is: [RSmith, smithr]
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: [(CBA717BC74064A8F7EC075DA95ACB8F6)]
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: [CN=TTTTTTTTTTTT]
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: []
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: []
10/28/2015 08:45:00 AM  HTTP JVM: Next value is: []


 You can see I cheated and did hard coded 5 cycles - so when there is nothing to display, you get an empty array. 

This may be useful for someone.

Cheers,
Brian


PS: If whoever does the Notes help wants to use this, or have me do the rest of the methods, I'll volunteer. BM

Wednesday, August 12, 2015

Bootstrap Progress Bars - sample database

I've been digging into Bootstrap for a bit now. One of the useful components is the progress bar. David Leedy did a great NotesIn9 on them and I followed it, and it was greatly valuable. I took his work and made a sample database. This is all his work, I just transcribed it (I changed the viewScope variable names however). Hopefully having this in a sample database will be useful.

Download the file

Cheers,
Brian




Tuesday, July 14, 2015

dataTable column width

In my last post, I'd say I'd look into controlling the column width. It's a setting:

<xp:column
  id="column4"

 style="width:5.0%">

so that was easy.

Cheers,
Brian

dataTable with Categories

I've been using DataTables for a number of things lately, where I need a bit more flexibility than a viewPanel, but I don't want to build it from scratch with a Repeat.

I'm currently working on process where I'm making a nsf to replace a MS Access database. So I'm having to adjust from the relational method. This means I need to use a key to look things up in a view to display the human friendly words rather than the code. So traditional Notes views don't do that. DataTables give me the flexibility I need. For part of this, I have 'events', and these will have one to several classes at each of these events. I want to hide the classes for each event until I click something to make it look neater and to save space.

DataTables don't have a native way to show categories, so I found one. I put a repeat in a column, and populate that repeat with a NotesViewEntryCollection from a value in a row of the DataTable. I tried to use the plus/minus icons like shown here in a great post by Ulrich Krause. But when I paged the icons disappeared. Both of them. So I used the basic idea, and put a link in that was always there to show the classes, and another link to hide them if desired. It works like I desire, so fine.

So this does what I wanted. I'm putting the code below. I have a few things to adjust. First, the classes should be in a table so they display better (I'm not putting it in to make the code a little shorter). Also, the columns resize when the repeat is expanded. Something I'll look into fixing after I post this.

Cheers,
Brian

<?xml version="1.0" encoding="UTF-8"?>
<xp:view xmlns:xp="http://www.ibm.com/xsp/core">
    <xp:this.data>
        <xp:dominoView
            var="view1"
            viewName="Event\Name">
            <xp:this.databaseName><![CDATA[#{javascript:var curServer = @Subset(@DbName(),1);
if(@Left(curServer.toLowerCase(), "/") == "cn=svrname") {
    session.getDatabase('
svrname/OU', 'foldername\\Data.nsf');
} else {
    session.getDatabase('', '
foldername\\Data.nsf');
}}]]></xp:this.databaseName>
        </xp:dominoView>
    </xp:this.data>
    <xp:dataTable
        id="dataTable1"
        rows="30"
        var="rowData"
        value="#{view1}">
        <xp:this.facets>
            <xp:pager
                partialRefresh="true"
                layout="Previous Group Next"
                xp:key="header"
                id="pager1">
            </xp:pager>
            <xp:pager
                partialRefresh="true"
                layout="Previous Group Next"
                xp:key="footer"
                id="pager2">
            </xp:pager>
        </xp:this.facets>
        <xp:column id="column1">
            <xp:this.facets>
                <xp:label
                    value="Event Name"
                    id="label1"
                    xp:key="header">
                </xp:label>
            </xp:this.facets>
            <xp:link
                escape="true"
                id="link1">               
            </xp:link>
            <xp:text
                escape="true"
                id="computedField4">
            <xp:this.value><![CDATA[#{javascript:rowData.getColumnValues()[0];}]]></xp:this.value></xp:text></xp:column>
        <xp:column id="column2">
            <xp:text
                escape="true"
                id="computedField5">
            <xp:this.value><![CDATA[#{javascript:rowData.getColumnValues()[4];}]]></xp:this.value></xp:text>
           
            <xp:this.facets>
                <xp:label
                    value="Date"
                    id="label2"
                    xp:key="header">
                </xp:label>
            </xp:this.facets>
        </xp:column>
        <xp:column id="column3">
        
            <xp:this.facets>
                <xp:label
                    value="Group"
                    id="label3"
                    xp:key="header">
                </xp:label>
            </xp:this.facets>
            <xp:text
                escape="true"
                id="computedField6">
            <xp:this.value><![CDATA[#{javascript:rowData.getColumnValues()[3];}]]></xp:this.value></xp:text></xp:column>
        <xp:column id="column4">           
            <xp:this.facets>
                <xp:label
                    value="Number"
                    id="label4"
                    xp:key="header">
                </xp:label>
            </xp:this.facets>
            <xp:text
                escape="true"
                id="computedField7">
                <xp:this.value><![CDATA[#{javascript:rowData.getColumnValues()[2];}]]></xp:this.value>
                <xp:this.converter>
                    <xp:convertNumber
                        type="number"
                        integerOnly="true">
                    </xp:convertNumber>
                </xp:this.converter>
            </xp:text></xp:column>
        <xp:column id="column6">
        <xp:panel id="mainpanel">   
            <xp:link
                escape="true"
                text="Classes"
                id="link6">
            <xp:eventHandler
                event="onclick"
                submit="false">
                <xp:this.script><![CDATA[var visibility = 'show';
XSP.partialRefreshGet("#{id:mainpanel}", {
params: {'$$xspsubmitvalue': visibility},
onComplete: function () {
    XSP.partialRefreshGet("#{id:secondpanel}", {
        params: {'$$xspsubmitvalue': visibility}});}
});]]></xp:this.script>
            </xp:eventHandler></xp:link>
        </xp:panel></xp:column>
        <xp:column id="column5">
            <xp:this.facets>
                <xp:label
                    value="Courses"
                    id="label5"
                    xp:key="header">
                </xp:label>
            </xp:this.facets>
            <xp:panel id="secondpanel">
            <xp:repeat
                id="repeat1"
                rows="30"
                rendered="#{javascript:context.getSubmittedValue()== 'show'}"
                var="rptRowData">
                <xp:this.value><![CDATA[#{javascript:var curServer = @Subset(@DbName(),1);
if(@Left(curServer.toLowerCase(), "/") == "cn=svrname") {
    var dataDb:NotesDatabase=session.getDatabase('
svrname/ou', 'foldername\\Data.nsf');
} else {
    var dataDb:NotesDatabase=session.getDatabase('', '
foldername\\Data.nsf');
}

var v:NotesView=dataDb.getView('Class Instance\\Event-Course');
var nvec:NotesViewEntryCollection=v.getAllEntriesByKey(rowData.getColumnValues()[2] + '', true);
return nvec;}]]></xp:this.value>
                <xp:text
                    escape="true"
                    id="computedField1">
                    <xp:this.value><![CDATA[#{javascript:rptRowData.getColumnValues()[1];}]]></xp:this.value>
                </xp:text>
                &#160;&#160;&#160;
                <xp:text
                    escape="true"
                    id="computedField2">
                    <xp:this.value><![CDATA[#{javascript:rptRowData.getColumnValues()[2];}]]></xp:this.value>
                    <xp:this.converter>
                        <xp:convertNumber
                            type="number"
                            integerOnly="true">
                        </xp:convertNumber>
                    </xp:this.converter>
                </xp:text>
                &#160;&#160;&#160;&#160; &#160;
                <xp:text
                    escape="true"
                    id="computedField3">
                    <xp:this.value><![CDATA[#{javascript:var cNumV:NotesView=database.getView('Course Number');
var cNVE:NotesViewEntry=cNumV.getEntryByKey(rptRowData.getColumnValues()[1], true);
if(cNVE != null){
return cNVE.getColumnValues()[1];
}
return "Course Name not found";}]]></xp:this.value>
                </xp:text>
                &#160;&#160;&#160;&#160;&#160;&#160;
            </xp:repeat>
            <xp:link
                escape="true"
                text="Close"
                rendered="#{javascript:context.getSubmittedValue()== 'show'}"
                id="link5">
                <xp:eventHandler
                    event="onclick"
                    submit="false">
                    <xp:this.script><![CDATA[var visibility = 'hide';
XSP.partialRefreshGet("#{id:mainpanel}", {
    params: {'$$xspsubmitvalue': visibility},
    onComplete: function () {
    XSP.partialRefreshGet("#{id:secondpanel}", {
    params: {'$$xspsubmitvalue': visibility}});}
});]]></xp:this.script>
                </xp:eventHandler>
            </xp:link>
            </xp:panel>
        </xp:column>
    </xp:dataTable>
    <xp:br></xp:br>
    </xp:view>




Saturday, July 4, 2015

StartKeys for categorized viewPanel and number column

In case this helps someone:

I have a database shared by a couple of departments, I use a field to segregate them. Each document has a MemberKey with a number value.

The first column is the department, sorted but not categorized, then a view were the column is sorted on numbers. As numbers they don't sort in the "proper" order. So I created a new column that padded it with zeroes to for the sort to be correct:

@Right("00000" + @Text(MemberKey);5)

So the third column is just the number, so it appears properly.

So I want this in an XPage viewPanel and to use the startKeys to get the the number desired.

I set the viewPanel to filter by the department name, and don't display the padded view. But it doesn't work. It doesn't work if I use the padded column either. It's because I'm getting just one category, so it's not really "starting" there.

I noticed the startKeys element can take a Vector, so I tried that. And it works.

I have a view panel that does not

I have a field  where I populate a viewScope called vFilter. If that is null, it return just one element in the vector, the department. Otherwise it returns a two element vector, with the department and the number I want to go to.

Here is my code in the startKeys element. (I'm using part of Thomas Adrian's Intrapages).

var query = new java.util.Vector();
var v = database.getView("(LookupUsers)");
var userdoc:NotesDocument = v.getDocumentByKey("User_UNID_" + userid,true);
if(userdoc!=null){
    query.add(userdoc.getItemValueString('regDepartment'));
    } else {
    query.add("Department not found");
    }
if(viewScope.vFilter != null){
query.add(@Right('00000' +  viewScope.vFilter,5));
return query;
}
return query;


Cheers,
Brian