Posts Tagged With: Xpages

Videotapes of #MWLUG2015

The whirlwind of MWLUG has passed for 2015. It was an outstanding conference, giving me an opportunity to explore a lot of new technologies, to learn some new techniques and to spend time with the peers that I usually only encounter online. I’ve said before, and I’ll say again, the greatest benefit of these conferences is sharing ideas and discussing issues outside the sessions. While you can get a good exposure to the information watching the videos, it’s never as much as you get from everyone being there. Additionally, my video list is subject to my own tastes. As such, it leans heavily toward development. I won’t apologize for that, but encourage anyone else who wants to start videotaping the administration sessions to do so.

I took my trusty video camera along, remembering to pack my best tripod this time. I’m not sure it’s so evident with the 2014 videos, but I’m not a good self-leveling cameraman. My Sunpak 70″ Ultra 7000TM Tripod has two bubble-levels and rises above the crowd, even when they’re standing. This is most helpful when I’m at the back of a big room and people need to walk in front of the camera. It probably also helps a little in assuring a better angle for the footage – nothing worse than staring up at the speaker. My Canon DM-50 Directional Stereo Microphone might actually be the coolest piece of equipment in the bundle (the Canon HG10 AVCHD video camera is old, but not cheap) and having found the back cover, it worked like a champ in Atlanta. The vaulted ceilings in Grand Rapids last year may have hindered the quality of the sound, but missing the cover couldn’t have helped. I might look at adding wireless microphones or getting some lights, since I know I can improve the image and sound quality further, though I be better served by buying some books and getting a steadier hand! Checking a few videos, I know I need more attention to lighting for certain, if not actual lights of my own.

The important thing today is to share our whole suite of videos from the conference. You could jump right to the entire MWLUG playlist, which includes some sessions from 2014, or use the chronological list here:

Wednesday sessions

CS101: Entrepreneurs Roundtable – What “They” Never Tell You About Owning a Business panel moderated by Lisa Duke
BP103: Let the Phoenix Rise: Rationalise your IBM Domino environment by Arshad Khalid and Stephanie Heit
AD108: Move Your XPages to the Fast Lane by Howard Greenberg

Opening General Session
“Everything Starts From A Dot”: The Elements and Principles of Design as the Visual Link to Innovation by Katherine Rhodes Fields
Establishing a New Culture of Design by Adam Cutler
IBM ESS Strategy Roadmap and Radar: A New Way to Work by Kramer Reeves and Peter Janzen

Thursday sessions

AD109: Navigating the Jungle of Modern Web Development by Shean McManus
The Greater Good of Social Collaboration by Louis Richardson
AD101: App.Next: The Future of Domino Application Development by Pete Janzen
AD107: Maven: An Exhortation and Apology by Jesse Gallagher
IV102: Graphs in Action by Nathan T Freeman

Friday sessions

AD117: Web Sockets – “Pushing” the web forward by Mark Roden
AD106: Just a View: An Introduction To Model-View-Controller Pattern by Ulrich Krause
AD114:Take Your XPages Development to the Next Level by Brad Balassaitis and Paul Calhoun
AD112: Real World Experience: Integrating DB2 with XPages by Steve Zavocki and Dwain Wuerfel
AD101: Design Matters by Keith Strickland and Bob Kadrie

All 16 videos published within a week. Last Wednesday at this time, Howard was wrapping up his session so that we could head down to the Exhibitors’ Showcase Reception. While all of these have gone out on twitter, there will be more postings and linkings to come. I think most of the slide decks are on people’s sites and some them have linked directly to the videos already. So, almost all of the 2015 work is done.

Spoke to my boss about MWLUG 2016 in Austin and she’s all in favor of it. Looking forward to seeing 250 of you there and many more of you in Orlando at the end of January. Now, if I can just get some work done on a session for Connect by the end of next week, I’ll be golden!

Categories: Conferences, Videos | Tags: , , , , , , , , , , , , , , , , , , , , , , , , , , | 7 Comments

Closing Unrelated Projects

When I first started trying to figure out XPages, I had all the default settings and I didn’t fiddle with them. I didn’t know what any of them were for and I still spend most of my time figuring out how to design things rather than how to handle my development environment, but, I am learning.

The first change I made was recommended by the folks over at Teamwork SolutioBuildAutomaticallyns, who’ve done some marvelous work on getting our main project rolling. They let me know that leaving the default setting of Build Automatically in the Project menu was a recipe for disaster in a multi-developer environment. I think it’s a bad thing even in a single-developer environment, because it constantly rebuilds your database, slowing down the design process as you wait for your CPU to catch up. If multiple developers are working in a single database, it’s likely to do a build in the middle of someone else’s work, screwing everything up. Of course, in any environment outside of Notes, builds and change control are a far more organized and normal process than we’ve dealt with. By making your builds only occur by conscious decision, you also move in the direction of all those other development environments. (Especially useful in preparing oneself for the inevitable technology and career changes that are normal for developers.)

CleanChoicesSo, on recommendation, I started always doing a Clean and then building just my specific database. Unfortunately, over the course of a day, like any normal Notes developer, I worked on several databases. Sometimes, these were completely unrelated. Why is this unfortunate? Well, my Clean & Build list got sloppy and crowded. Sometimes, in order to make my list look cleaner, I’d close my Designer client and restart it. I knew there was a way to clean up the list without doing that, but it was easy.

Now, I would think that having all those projects open would eat up memory and that removing them would somehow free up memory. Heck, I even thought that closing the Designer client would free up memory. It doesn’t appear to do so, but that might just be the random and anecdotal nature of my “testing”.

Nonetheless, I wanted a cleaner list, so I fiddled around and, I found what I was looking for. CloseUnrelatedProjectsIf you use the Navigator view in your Designer’s Eclipse perspective, you can right-click on the one database you actually want to appear in your Clean & Build dialog, then down toward the bottom choose Close Unrelated Projects. Then, your list looks nice and neat. I wish I could say this speeds processing or limits memory use, but the only performance increase I’ve seen is the change to the dialog box. Hopefully, Notes 9 will provide better memory management in this regard, but even if it does not, my need for a neater workspace will compel me to use this process.

I’d appreciate your thoughts and comments on this, especially if you’ve any speculation or data on performance improvement using this.

Oops! I forgot to mention the biggest reason for closing projects – Search. If you use <ctrl-H> to search your design elements for a string (which I do pretty often) then it will search all open projects. If you have several open projects you’re not working on, you get a lot of extraneous results and it takes far longer to complete. Closing those unrelated projects eliminates the wasted time.

Categories: IDE | Tags: , , , | 2 Comments

Creating one-to-many linking in Xpages

As I noted in my prior post, our new XPages application will need links from Requisitions to all Purchase Orders that are created from that Requisition. Now, in regular old Notes, I’d handle this just by plopping down a single-category embedded view, using the Requisition’s ID to find just the right Purchase Orders. Since embedded views already allow you to open the document underneath, my work would be done.

Fortunately, having found that Server Side Javascript is not frightfully different from LotusScript. You already have the basic understanding of the document object model from doing LotusScript, so it’s just a matter of figuring out the syntax, right?

Since I want to display a set of links to the associated Purchase Orders, I decided the cleanest way to do that was using a Repeat Control. Unfortunately, knowing the tool I needed didn’t resolve the problem by itself.

First, I had to build the values that would go into my Repeat Control. I thought about binding the view here, but our data doesn’t reside in the same database as the XPage designs. That means I’d have to compute which database I needed and, so far, that felt beyond my talents. Fortunately, the wonderful folks over at Teamwork Solutions provided us with a quick way to get a handle to the database, a getDb function. So, rather than trying to figure out how to squeeze that into a binding, I stuck to my LotusScript roots and got a NotesDocumentCollection from the view.

	<xp:this.value><![CDATA[#{javascript:
 		var db:NotesDatabase = getDb("tamisDb");
 		var poView = db.getView("PObyProcReqDocID");
 		var docCollection = poView.getAllDocumentsByKey(getComponent("docID1").getValue());
 		return docCollection;}]]>
 	</xp:this.value>

So, then, in my repeat, I can just refer to each document, pulling the values I want.

I always try to give my objects names that identify them clearly. My very first paid programming assignment was when I was pursuing my degree in Political Science, studying the Soviet Union. I worked at the National Superconducting Cyclotron Lab. It was a great place to work. Now, they don’t normally hire social studies majors to write code, but I hired in as a receptionist, then started working for the guys in Operations, walking around recording numbers on dials and checking on things. My boss knew I’d been a computer science major, so he guided me into re-writing their help document database. Every module in the database was named after a woman in his life. They were suitable names for him, because he knew the woman and the module names fit their personalities. I didn’t and I knew the next guy wouldn’t either, so I gave them all nice, functional names.

Why do I digress? Well, XPages is so eager to write code for you, that it assigns object names with object type and a number. I think a lot of people leave it that way, but when I’m in there, I need to assign names that fit. Sadly, I always end up with rowData as the object name for my repeats. I don’t know if changing from that had doomed my early repeats or if it’s just superstitious, but I leave it as rowData.

So, back to the completed code. Our ‘value’ section is there, identifying the NotesDocumentCollection we need, of all Purchase Orders documents that belong to the Requisition. For each one, we establish a link, labelling it by grabbing a field value, then using a Simple Action to open the pro_purchaseOrder XPage that displays Purchase Orders and using the UNID from the document selected as our rowData.

	<xp:repeat id="purchaseOrderLinkRepeat" rows="30" var="rowData" repeatControls="false" removeRepeat="true">
		<xp:this.value><![CDATA[#{javascript:
			var db:NotesDatabase = getDb("tamisDb");
			var poView = db.getView("PObyProcReqDocID")
			var docCollection = poView.getAllDocumentsByKey(getComponent("docID1").getValue());
			return docCollection;}]]>
		</xp:this.value>
		<xp:link id="poLink">
			<xp:this.text><![CDATA[#{javascript:"Purchase record: " + rowData.getItemValueString("TSWFNumber");}]]>
			</xp:this.text>
			<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
				<xp:this.action>
					<xp:openPage name="/pro_purchaseOrder.xsp" target="openDocument"
						documentId="#{javascript:rowData.getUniversalID();}">
					</xp:openPage>
				</xp:this.action>
			</xp:eventHandler>
		</xp:link>
	</xp:repeat>

Honestly, that little slice of code took me several days to get my head around. I wasn’t staring at the screen the whole time, but the stops-and-starts of trying one approach and then another were tremendous. Those hurdles truly point out that a seasoned developer might well accomplish in an hour what it takes a new developer (or one new to the language) an entire week to do. Now that I have it under my belt, my team and I will be reusing this all over the place. I hope you can as well.

Categories: Server-Side Javascript | Tags: , , , , | 1 Comment

Creating a one-to-one linking in XPages

In our current project, we create Requisitions with one XPage and then create Purchase Orders with another. Each Requisition may result in many Purchase Orders, but a Purchase Order can only contain line items from a single Requisition. Naturally, the customer wants to be able to move seamlessly from the Requisition to any of the corresponding Purchase Orders and vice-versa.

I wasn’t sure how I’d do this in XPages, but knew I could do it for Notes users without a lot of coding and I could even make it look like web link.

One-to-One In Notes

In regular old Notes, this was very simple. On the Purchase Order form, where I wanted my link I typed Open Procurement Request, then highlighted it and clicked from the top-line menu, Create – Hotspot – Action Hotspot. I made two formatting changes (underline and deselecting the border around the hotspot) 1 and switched the action to run LotusScript. Nice, simple code makes that hotspot open the Requisition:

Sub Click(Source As Button)
	Dim session As New NotesSession
	Dim ws As New NotesUIWorkspace
	Dim thisdb As NotesDatabase
	Dim view As NotesView
	Dim uidoc As NotesUIDocument
	Dim thisdoc As NotesDocument
	Dim reqdoc As NotesDocument
	Dim luvalue As Variant

	Set uidoc = ws.CurrentDocument
	Set thisdoc = uidoc.Document
	luvalue = thisdoc.GetItemValue ( "ProcReqDocID" )

	Set thisdb = session.CurrentDatabase
	Set view = thisdb.GetView ( "LUProcByDocID" )
	Set reqdoc = view.GetDocumentByKey ( luvalue(0) )

	Print luvalue (0)
	If Not reqdoc Is Nothing Then
		Call ws.editDocument ( False, reqdoc )
	End If

End Sub

One-to-One In XPages

Having done it in Notes, I had some guidelines for how I wanted to do it in XPages, rather than just shooting in the dark. I also added display of the requisition number, which turned out to take a few lines of code as well.

	<xp:link escape="true" id="requisitionLink" target="_blank">
		<xp:this.rendered><![CDATA[#{javascript:poDoc.getItemValueString("ProcReqDocID") != "";}]]>
		</xp:this.rendered>
		<xp:this.text><![CDATA[#{javascript:
			var reqID = poDoc.getItemValueString("ProcReqDocID");
			var db:NotesDatabase = getDb("tamisDb");
			var reqView:NotesView = db.getView("LUProcByDocID");
			var reqDoc:NotesDocument = reqView.getDocumentByKey(reqID);
			var reqNumber = reqDoc.getItemValueString("TSWFNumber");
			return "Requisition: " + reqNumber; }]]>
		</xp:this.text>
		<xp:eventHandler event="onclick" submit="true" refreshMode="complete">
			<xp:this.action>
				<xp:openPage name="/pro_procurementRequest.xsp" target="openDocument">
					<xp:this.documentId><![CDATA[#{javascript:
						var reqID = poDoc.getItemValueString("ProcReqDocID");;
						var db:NotesDatabase = getDb("tamisDb");
						var reqView:NotesView = db.getView("LUProcByDocID");
						var reqDoc:NotesDocument = reqView.getDocumentByKey(reqID);
						return reqDoc.getUniversalID();}]]>
					</xp:this.documentId>
				</xp:openPage>
			</xp:this.action>
		</xp:eventHandler>
	</xp:link>

While this was somewhat intimidating, it ended up being not that hard. I will admit that it did take me a whole day to figure out, but it gave me the courage to try tackling linking in the opposite direction, our one-to-many link. For that, I had to expand my recently gained knowledge of repeats. More on that later.

My recent knowledge gain for repeats is thanks to TeamStudio’s webinar on mobile applications. Go figure. As I implement the mobile application that the webinar guided me through building, I’ll blog about that as well. For now, go check out the video.

1) Does anyone use those borders around the hotspot anymore? Since it looks so hideously and is therefor unusable shouldn’t it no longer be the default? Shouldn’t it instead default to underlined?

Categories: Server-Side Javascript | Tags: , , | 1 Comment

Handling numeric ranges in text

I’ve often said in the last six months that the frustrating thing about XPages in comparison to “old Notes” is that sometimes things that were easy before, are now hard. So many of us have 12-18 years of Notes development and can code in LotusScript basically off the top of our heads that doing XPages is almost like starting over.

Such is the case I’ve recently had with handling some text keywords that determine dollar ranges for workflow routing. In the original XPages design, the dollar ranges were in a combo box, for the user to select manually. As such, all four range values were simply put as text values in a multi-value text field in a keyword document. Well, since asking (or trusting) one’s users to select the dollar range seems excessive when we could simply compute it for them, I decided to modify that part of the XPage I’d inherited.

Intially, the four values used in the combo box would return an alias value bound to a field on the document, so the keyword document had these values:

Under $500|1
$500 to $3,000|2
$3,001 to $150,000|3
Over $150,000|4

In my simple world of formula language and LotusScript, I would have been able to use a simple formula that included @TextToNumber, some @RightBack’s and @Left’s to establish what the range border values are. Tossing it into Client Side Javascript (CSJS), it vexed me. So, rather than handle it, I created a range keyword that just had the numeric values and a text keyword that had the nice display text. I promised myself I’d get back to it and in one of the miracles of the modern era, I got back to it within a few weeks (after Connect-o-Sphere both enthused and confused me in the same week).

There’s a computed field used to determine the total value of the purchase order, so I had snuck my code for determining the dollar range right into that formula. This intrigues me because I can have code to recompute the dollar range value only when that total value changes – an option I wouldn’t have had under “old Notes”, where it would have recomputed every time.

I realized that if I’m computing the text to display the dollar range anyway, I could drop the aliasing off the end of the keyword values, which should make them more accessible to my local admins for configuring their workflow. I used Javascript to bind the computed combo box value as follows:

var choices = new TS_Keywords().Lookup("Procurement / Checklist dollar ranges", true);
if (poDoc.isEditable()){
	var number = viewScope.dollarRange; }
else { number = poDoc.getItemValueInteger("DollarRange") };
if ( number > 0 ) {
	number = number-1;
}
return choices[number];

TS_Keywords was written for us by Teamwork Solutions, but basically we’re just getting the multi-value text field with it.

So, to handle that multi-value text field, I needed to use several String methods in Javscript: slice, length, replace and parseInt. I was rather surprised that it both looks like such a complex line of code, but is also relatively simple.

//compute dollarRange and store as a viewScope variable

var number = 4
// compute numeric values of the checklist ranges from the text keyword
var rawlevels = new TS_Keywords().Lookup("Procurement / Checklist dollar ranges", true);
var levels = new Array (rawlevels.length);
for (var i=0;i<rawlevels.length;i++) {
	var space = rawlevels[i].lastIndexOf("$");
	levels[i] = parseInt ( rawlevels[i].slice ( space + 1, rawlevels[i].length ).replace(",","") );
}

// find which range the total falls into
if ( thisVal <= levels[0] ) { number = 1 };
if ( thisVal > levels[0] && thisVal <= levels[1] ) { number = 2 }; 
if ( thisVal > levels[1] && thisVal <= levels[2] ) { number = 3 };
poDoc.setValue("DollarRange",@Integer(number));

While I’m sure this is not the most efficient way to handle this, it avoids the multiple keyword nightmare I was going to foist on those local administrators and might guide someone generally in the direction of solving their own coding problems.

Categories: Client-Side Javascript | Tags: , , , | Leave a comment

Copying views from one database to many

Recently, one of our internal clients asked if we could change who could see a button on one view that is in many of our databases. That sounds pretty easy, right? All you have to do is change the template and those changes will be pushed by the Designer task into every database.

Well, unfortunately, while almost all of the 65 databases in question contain the same view, some of those views don’t link back to any template.

I’d learned a while ago that the old Notes.Net forum was no longer particularly active and that the community had decided to move questions to Stack Overflow.

To digress for a moment, Stack Overflow is part of the Stack Exchange “network of communities” and it’s a great place to both seek and provide answers with experts and budding experts. It was founded in 2010 by one of my favorites in the industry, Joel Spolsky, and Jeff Atwood. Joel’s blog, Joel on Software, provided me with a lot of insights into programming, running a business, dealing with people and, oddly enough, with the first news I had of trouble on the morning of 9/11.

So, if you have a Notes, XPages or other problem, go there and ask. I asked around on Stack Overflow (link) and got a recommendation on how to deal with it. Actually, I got a couple of ideas to choose from and Panu Haaramo’s idea was the best. Basically, get a handle to the view by it’s UNID and copy it to the destination database using XPages.

I put a combobox (fileChoices) on the page to allow the user to select which database to push to, hardcoding in the view name, but it could easily be generalized and looped.

// get a handle to this database
var thisdb:NotesDatabase = session.getCurrentDatabase();
// get server
var server = "MyServer/MyCompany";
// get filepath
var filepath = getComponent("fileChoices").getValue();
getComponent("status").setValue("Searching for "+filepath);
// get a handle to the destination database 
var dbTarget:NotesDatabase = session.getDatabase(server,filepath);
// delete the Manuals view
var oldView:NotesView = dbTarget.getView("Manuals");
if ( @IsNull (oldView) ) { getComponent("status").setValue("Null"); 
} else {
    getComponent("status").setValue(getComponent("status").getValue()+", Trying "+ dbTarget.getTitle());
    try { oldView.remove();
        // get a handle to this Manuals view
        // copy the view to the destination database
        thisdb.getDocumentByUNID(thisdb.getView("Manuals").getUniversalID()).copyToDatabase(dbTarget);
        getComponent("status").setValue(getComponent("status").getValue()+", Updated on "+filepath);
    }
    catch (ex) {
        getComponent("status").setValue(getComponent("status").getValue()+", No update for "+filepath);
    };
}

Any thoughts on how to improve the code (especially the null-checking, which I cannot tell whether it does any good or if the try-catch ends up doing everything) will be greatly appreciated, with credit provided and the code updated.

Somehow, when I posted this internally, it won “Most Popular Newsfeed of the Month” at our office in January. When I tell you I work for an international development company, that seems to make sense… until I point out that the development the rest of the company does is the other kind of development. That is projects designed to help people in developing countries. So, rather than show how well-received my post was internally, it shows that we’re still early on in our efforts at Social Business.

Categories: Utilities | Tags: , , | 3 Comments

Blog at WordPress.com.

%d bloggers like this: