XPages – Saving data sources bound to a panel – a lesson learned

In this article I will highlight/document an issue which I came across today – using a Save Button and a Document Data source bound to a panel.

so this is what I learned today

When you have an xpages document data source bound to a panel

 <xp:panel id="widgetContentsWrapper" styleClass="widgetContentsWrapper">
  <xp:this.data>
   <xp:dominoDocument var="widgetsDoc" formName="Widgets"  scope="request">
   </xp:dominoDocument>
  </xp:this.data>

and a save button to “saveDocument”

  <xp:button styleClass="btn btn-primary modal-ok" value="Submit Button" id="button1" disableTheme="true" >
   <xp:eventHandler event="onclick" submit="true" refreshMode="complete">
    <xp:this.action>
     <xp:actionGroup>
      <xp:saveDocument var="widgetsDoc"></xp:saveDocument>
     </xp:actionGroup>
    </xp:this.action>
   </xp:eventHandler>
  </xp:button>

The button must be within the panel – otherwise for absolutely no apparent reason it just does not work. I checked the form – yes data was being submitted but apparently not saved.

I have never experienced this before because I have never used a data source bound to a panel before – now I know better!

I hope you do not have to share my pain…

DCLUG – October 24th – Toolfest Double Header – Teamstudio and Ytria

I am very pleased to announce the next  DC Lotus User Group on October 24th will be a double header with Ben Menesi and Jon Andrews from Ytria and Teamstudio respectively

Both of these companies have played an huge part in providing the tools that administrators and developers use on a daily basis worldwide. I know I have sung the praises of Teamstudio products before and have been instrumental in bringing them to the new companies I work for. 

For the first time ever this will be a morning meeting an for more information please check out the meetup site

http://www.meetup.com/DC-Lotus-Professionals/events/141113842/

In addition to showing off their latest wares in back to back sessions, they will stick around for a lunchtime “Stump the LUG” session where we invite you to share your own technical pain points with the entire group and to discuss how you can address them (perhaps with tools you didn’t know you needed). 

Here’s what’s in store for you at this must see event:

9:30 AM – Coffee & Refreshments

9:45 AM – Welcome and Quick Community Update

10:00 AM – Session 1: Ytria’s EZSuite of products help administrators and developers deal with a large variety of issues: whether it’s about ACL management, agent troubleshooting, or even replication problems, Lotus Domino often lacks a much needed overview, as well as mass-problem solving capabilities. Using scenarios from the field, we’ll discuss why the tedious and manually-intensive methods you use to address them are due for an extreme makeover. For example, we’ll spend time with alternatives to the well known task of writing agents for data manipulation that you’ll never use again.

11:00 AM – Session 2: Teamstudio’s latest killer tool Teamstudio Unplugged moves them in a new direction by providing a practical and compelling toolset for developers to surface existing Notes client apps as native apps on the iPad and other mobile devices. The Lotus Notes client pioneered secure, offline-capable business applications and Teamstudio Unplugged helps bring that same capability to a new generation of mobile devices. Unplugged cross-platform mobile apps are developed using XPages through the familiar Domino Designer interface, and the platform ships with three pre-unpluggified IBM templates (Journal, Teamroom, and Doc Library). In this session we will demo Teamstudio’s own “Mobile Approvals” template, as well as show you how to customize these templates, for example by adding camera integration for uploading photos.

12:00 – Lunchtime “Stump the LUG” Discussion

Thanks Bruce

I am a late comer to the OpenNTF community as I have explained before this was more due to the circumstances of my job in the mid 2000s shifting me away from development but I restarted development in 2011 and have not looked back.

So I have no known Bruce personally for much more than 18 months but I have know “of” him for much longer (obviously).

Unknowingly Bruce was the second person (other than my friends) to ever follow me on twitter (more here) and even by that simple act that was encouragement to get involved.

Since I have known him Bruce has been a good friend and a great example to me of how to look beyond what I am doing today and look to the future. Bruce has opened opportunities for me which I could have only dreamed of once upon a time and for that I will forever be grateful.

I see Bruce not only as a friend but a mentor of sorts, I have learned from him and will continue to do so.

Without Bruce’s involvement in OpenNTF I expect our paths would not have ultimately crossed, but I am very glad they did.

Thank you Bruce for following me on twitter, encouraging me and ultimately being someone I consider a friend beyond just the community.

jQuery event delegation

So it turns out that I may have blogged a moment too soon over the weekend….

While the following code works

	$('.modal').on('shown.bs.modal', function () {
		$('FORM')
			.append($('.modal-backdrop, .modal-scrollable'));
	})

It only works the FIRST time – and if you had tested your code properly Mark you would have found this out to be the case. Too eager to blog weren’t we Marky……*pouts*

So anyway like all mistakes a good excuse for more learning – and in this case it wasn’t so much learning it was more muscle memory and more (oh duh Marky – which happens a lot)

The problem
What is happening is that the original code above is only binding to the modal once – and once the modal is being shown on the page and then hidden again apparently that event binding is being lost. I have no proof of this but I suspect that the DOM objects are being destroyed and recreated which is what is causing the loss 😦

The solution
Event delegation – oh it is a wonderful thing once you get your head around it and extremely powerful – go read up about it here and check out the last example specifically

What I was doing is binding to the exact element and once that element is gone – no more binding.

What is Event Delegation?
Event delegation is basically the same thing as event binding, but it works on any matching element whether it exists yet or not.
Que?
What I mean to say is that this piece of code REALLY WORKS and I will explain

$('body').on('shown.bs.modal', '.modal', function () {
    $('FORM')
        .append($('.modal-backdrop, .modal-scrollable'));
})

In this example we are:

  • Selecting the Body
  • And then in the shown.bs.modal event of anything matching the .modal selector
  • do stuff as before.

So if you imagine a simple analogy of feeding a dog.

If you have a child – let’s say your son and you tell him that on the “breakfast event” put food in that exact blue dog bowl – he will do that

Being the obedient child that he is he will fill that bowl every day when it appears.

But being the obstinate child he is, when you replace *that* blue bowl with a new one he will not fill it because you told him to fill the old one

A fight ensues and he loses minecraft privileges!

You then change your instructions:  On the “breakfast event” put food in any dog bowl which appears in the Kitchen. So even if you replace it every day he will have to still do as he is told and fill the bowl.

That is what Event Delegation is – telling the DOM to do things to anything which exists now and anything which appears in the future.

The way it works is because of the second selector – you are telling the DOM body to look for anything with a shown.bs.modal and bind to it. So even though my original dialog apparently lost the binding, in the new case it is automatically re-applied because of the delegated event on the Body

If only I had remembered that before blogging earlier…….

Ah well – we all learned something new

I wonder what I missed today………..

Making XPages partialRefresh work in a bootstrap 3 dialog box.

In this article I will improve on the solution I posted last week to my form submittal problem and actually provide a more elegant and robust solution.

The problem

Dave Leedy

I mean to say that Dave Leedy posed a problem to me last Friday which gave me pause for thought. Obviously he had come across this issue before. “Marky have you tried to do a partialRefresh inside of the bootstrap modal dialog?”. I had not and I knew that I had plans to…..

Then it struck me – of course the partialRefresh can’t work in the dialog because the dialog is outside of the form. The partialRefresh relies on the ability to post data back to the server (via the form) and the collect the response and re-draw. Of course it isn’t going to work.

The solution

As I said the other day – the bootstrap dialog is not purposefully removing itself from the form, it is moving itself to the end of the DOM tree. Why? I couldn’t say but it seems to be pretty consistent. So on the assumption it is nothing to do with the “form” I figured the easiest solution would be to put it back *into* the form once it was visible.

As we saw before when the modal is created there are two elements moved to the end – the dialog itself and the faded out background

b3

Using a bit of jQuery magic we select those two DIVs and “append()” them back into the form. Using the append() method they are always added to the end of the target DOM element container. You should add this code to every page where you have a dialog. Add this code to a CSJS library and include it on every page where you have a bootstrap modal.

$(document).ready( function(){
	$('.modal').on('shown.bs.modal', function () {
		$('FORM').append($('.modal-backdrop, .modal-scrollable'));
	})
})

  What does that mean exactly?

  • In the ‘shown.bs.modal’ event of the selected $(‘.modal’)
  • Get the $(‘FORM’) and .append() into it the two selected $(‘.modal-backdrop, .modal-scrollable’) DIVs

and then you get this

b4

Once the modal is then inside the dialog we can post it to our hearts content.

We can prove that with a simple @Random within the dialog box and a quick code snippet in firebug

We add a “random” class to the computed text so that we can select it

b5

We then load up the dialog

b6

Run the JavaScript to cause a partialRefresh

b7

Et voila a partialRefresh with a dialog. It also works of course with XPage controls and buttons and the like but this was just a simple way to demonstrate how to do it

Conclusion

Once we understand the DOM changes which are being made for a bootstrap dialog we are able to use jQuery to easily manipulate the  resulting DOM to be able to make our application work.

 

ADDENDUM – updated

Please see the jQuery Event Delegation blog post to understand why this approach is limited and needed to be updated….new solution provided

Why does hitting submit from within a bootstrap dialog not work?

In this article I will show why submitting an XPage from within a Bootstrap dialog does not work correctly and also discuss some options for working around the issue.

Introduction  

The bootstrap modal rocks (In Marky’s opinion) and it can be enhanced with the Bootstrap-Modal extension which gives greater control and more options. But I came across an issue recently whereby I could not “Submit” from within a dialog. Well ok I could submit but none of the fields seemed to be updated.

The Dialog

Initially the bootstrap dialog code sits within the XPage quite happily and it is hidden by CSS.

b1

But what happen when the dialog is displayed on the page? The HTML is manipulated and the modal dialog HTML code is moved within the DOM and apparently outside of the <form> tags.

b2

I do not think that it is intentionally moved outside of the form – what is really happening is that it is being moved to the last entry within the DOM – the following highlights it better – it is moved to the last DOM element within the body

b3

What does this mean?

Well what it means is that then you have a custom control displayed within the Dialog, and you try to hit a submit button from within the dialog, the fields are not “in the form” and therefore are not submitted back to the server. Simple answer once you figure it out (an “oh well no duh” moment)

So what can we do about it?

We have a number of options all of which are to do…….

  1. Do not submit from a dialog (not always practical)
  2. Looking at the bootstrap modal API event (http://getbootstrap.com/javascript/#modals-usage) we can see that there is a hidden.bs.modal event with this we know that the modal is closed. Once the modal is closed it is reinserted back into the DOM correctly in the same place as it was originally. Once that happens if the form is submitted then the fields are in the “<form>” tag and we are good to go.
  3. We can manipulate the form to “re-surround” the whole page including the dialog
  4. We can insert a new <xp:form> tag within the dialog and submit that one instead http://stackoverflow.com/a/9349329/1171653
    1. (in this author’s opinion embedded forms are just asking for trouble and should be avoided)

Whichever you prefer to do depends on your circumstances and needs from the code. If anyone has any other suggestions I would love to hear them!

Conclusion

Love Bootstrap, Love the Dialog, but like everything, sometimes you need to get a better understanding of how it works and tweak it a little.

Inserting a new Row into a viewPanel (any table) using jQuery

This is a short and sweet blog post showing how to programmatically add a new line into a table using jQuery.

Introduction

I am playing around with some column ordering and I want to add some dummy data to a table – rather than go to the trouble of doing it on the back end I decided to do it using jQuery so that i can easily change the values using Firebug

The .before() function

The .before() function inserts a set of HTML “before” the selected DOM element. It has a companion .after() function which unsurprisingly adds HTML after a DOM element.

Inserting a new row
I want to add my new line as the top row of this table

nr1

and I do this by:

  1. Selecting the first child in the viewPanel (class=.xspDataTable) tbody
  2. adding the new row before it
$('.xspDataTable tbody')    //select the tbody within the viewPanel
        .children(':eq(0)') //select the first child therein
        .before("<tr class='marky'><td>9</td><td>3</td><td>1</td><td>7</td></tr>")

Now why do I do that you ask? – good question. As I found out it turns out that the viewPanel has a TR in the header before the TBody – so if I select the first row in the table then I do not get the first “data row” so I go for the first child in the TBODY which is the TR element representing the first row I am looking for.

Here is what we get – short and simple

nr2

The code change looks like this

nr3becomes

nr4

 

 

Decoupling your CSS from your JavaScript, a “well no duh” moment

This weekend I had one of those “oh DUH” moments which I have been struggling with for quite some time. How can I better structure my jQuery selectors and make the code more maintainable? I came across this excellent article – Decoupling your HTML CSS and JavaScript and it all came into focus.

The problem

Using JavaScript selectors (dojo or jQuery) in XPages can be a problem because of the id naming scheme used by the JSP generator “id=”view:_id1:_id2:link5” and how this falls over in a selector. So an alternate to not having to mess with is attributes is to use class selectors $(‘.class’) which is actually much simpler and less troubling to get your head around.

When you are using class selectors for a DOM element which already has a class then awesome I don’t have to add any more classes. Using this bootstrap example there are multiple classes I can get a hold of to manipulate the dialog contents.

 <div class="modal fade myModal" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
			<button type="button" class="close modal-maxmin" aria-hidden="true">
				<i class="icon-external-link"> </i>
			</button>
			<button type="button" data-dismiss="modal" class="close" aria-hidden="true">
				<i class="icon-remove"> </i>
			</button>
          <h4 class="modal-title">modal-title</h4>
        </div>
        <div class="modal-body">
         modal-body : HERE GOES THE MESSAGE
        </div>
        <div class="modal-footer">
	        <div class="btn-group">
	          <button type="button" class="btn btn-default modal-cancel" data-dismiss="modal">CANCEL</button>
	          <button type="button" class="btn btn-primary modal-ok">OK</button>
	        </div>
        </div>
      </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
  </div><!-- /.modal -->

To add something to the body of the dialog I would do something like this

  $(".modal-body").html('Hi Marky')

The other problem

This example is very “coupled” code whereby my JavaScript selector is coupled to the real class file used by the HTML code. In reality what it means is that if I have to change the classname for some reason (hmm an example – oh I don’t know – going from Bootstrap2 to Bootstrap3 for example) then my JavaScript breaks down. While tightly coupled code is easy to follow, easy to create initially, it can be an absolute nightmare in the long run.

The epiphany moment

As I am reading Philip Walton’s article  I am struck by the “oh well no duh” moment when he talks about using js-* as a naming convention for classes which only exist for JavaScript selection.

  • My personal recommendation is to use a prefix for all JavaScript hooks. I use js-*. That way, when a developer sees such a class in the HTML source, she’ll know exactly where to look to discover its purpose.

Well no duh – brilliant idea!

In all senses this makes perfect sense:

  • The developer does not have to search through CSS files looking to see if you used the class as a selector as a real CSS marker
    • (well ok they changed something and the CSS broke, then they started to look for it)
  • It is immediately apparent from looking at the HTML that there is some dojo or jQuery selection/manipulation going to go on in this area because of the js-* class naming scheme
  • Within eclipse you can do a quick search and find out what is trying to manipulate this area before you go and ruin it

The new code

A very simple change to the modal-body but this then decouples my code form the bootstrap code – allowing me to make changes to the bootstrap classes int he future without breaking my JavaScript

 <div class="modal fade myModal" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel" aria-hidden="true">
    <div class="modal-dialog">
      <div class="modal-content">
        <div class="modal-header">
			<button type="button" class="close modal-maxmin" aria-hidden="true">
				<i class="icon-external-link"> </i>
			</button>
			<button type="button" data-dismiss="modal" class="close" aria-hidden="true">
				<i class="icon-remove"> </i>
			</button>
          <h4 class="modal-title">modal-title</h4>
        </div>
        <div class="modal-body js-modal-body"> <!-- js-modal-body change here -->
         modal-body : HERE GOES THE MESSAGE
        </div>
        <div class="modal-footer">
	        <div class="btn-group">
	          <button type="button" class="btn btn-default modal-cancel" data-dismiss="modal">CANCEL</button>
	          <button type="button" class="btn btn-primary modal-ok">OK</button>
	        </div>
        </div>
      </div><!-- /.modal-content -->
    </div><!-- /.modal-dialog -->
  </div><!-- /.modal -->

To add something to the body of the dialog I would now select the js-* class not the modal-body itself

  $(".js-modal-body").html('Hi Marky')

Comment

One of the things I love about my career is that it is an “always learning” experience for me. There are times like this where you think to yourself that is an awesome idea and you are very happy to learn it – and at the same time feel so stupid that you didn’t think of it yourself before 🙂

EXTJS in XPages #17 – Manually Updating row data via REST

In this article I will demonstrate how we can use the same REST service we used to populate our grid, to accept an update to one of the row values.

EXTJS in XPages series
Here are links to all of the previous articles in this series

Demonstration
The EXTJS in XPages demonstration database can be found at http://demo.xomino.com/xomino/Extjs.nsf/xContextMenuRESTUpdate.xsp

Download
The sample database that will accompany this series is available from the menu in the live demo database from this link – http://demo.xomino.com/xomino/Extjs.nsf

Introduction

In the last article we saw how we can easily create a context menu and in this article we are going to add the icing on the user experience – updating the data on the server via a REST service. Once again in this incremental series, this is a small mount of additional effort to effect a large benefit for the end user experience.

r1

How does that work?

In the XPages world we are able to update a document via a REST service using the URL format:

  • /path/database.nsf/rest.xsp/restPathInfo/UNID

To that URL we have to post (or in this case PUT) a JSON string in the format {“field”: “value”, “field2”: “value2”}

To achieve this we have to “handle” the context menu in the following manner:

var approveAction = Ext.create('Ext.Action', {
    icon   : 'images/add.png',  // Use a URL in the icon config
    text: 'Approve Users',
    disabled: false,
    handler: function(widget, event) {
        var selection = Ext.getCmp('myPanel').getSelectionModel().getSelection()[0];
        buildSubmit.updateREST(selection, "Approved")

    }
})

In this handler we get the selected document, and pass that “selection” and the status value to be updated to the buildSubmit.updateREST function.

Within the function we:

  • Build the JSON data string
    • {‘unid’: selection.data[“@unid”], ‘status’: status}
    • The @UNID is pulled from the REST service property of this document
    • The status is passed into the function “Approved”
  • Pass the string array to the updateStatus function which in turn
    • Creates an AJAX “PUT” request to the REST service
      • xRestService.xsp/byFirstNameFlat/’+data.unid
    • If this successfully updates we then update the row field value with the “Approved value”
var buildSubmit = {

	updateREST: function(selection, status){
		var data = {'unid': selection.data["@unid"],
					'status': status}
		buildSubmit.updateStatus(selection, data)
	},
	updateStatus: function(selection, data) {
		  $.ajax({
			   type: 'PUT',
			   contentType: 'application/json',
			   url: 'xRestService.xsp/byFirstNameFlat/'+data.unid,
			   dataType: "json",
			   data: JSON.stringify(data),
			   success: function(response, textStatus, jqXHR){
				  //update the cell in the grid
				  selection.set("status",data.status);
				},
				error: function(jqXHR, textStatus, errorThrown){
					   console.log('sort order error: ' + textStatus);
				}
		  	});
	}
}

When the data is successfully updated in the grid the EXTJS code automatically adds a marker which indicates that the contents of this field have been changed

r2

Looking at this through Firebug

As we can see from the image below – the “PUT” request is sent to the URL
http://copper.xomino.com/xomino/Extjs.nsf/xRestService.xsp/byFirstNameFlat/B73326B7CDBEFAD385257B1B00254C58
and the JSON is successfully sent to the REST service.

r3

 

Conclusion

There are a few of things to think about in this example:

  1. Once again a few simple lines of code provides a huge benefit to the user.
    1. Being able to update data directly from the grid means they can get their job done faster
    2. Being able to update via a right click action menu means they can get their job done faster
  2. Being able to update the grid field values programmatically means we do not have to reload the grid data
    1. If this is the only point you take away form the this article this is the most important.
    2. Reloading grid data has a cost, in data consumption on the server, time expended to download, time to redraw and most importantly time wasted for the user getting a confirmation that their data was updated. If you have a large number of data rows and the update is in the order of seconds then the user has to wait. Updating a single field of data is instantaneous and the user experience gratification is immediately satisfied.
    3. If you are updating data within the grid itself – DO NOT reload the grid data from the server – EVER – plan your user experience better !
  3. Using the jsonviewservice out of the box EXTLib REST service allows me to make field updates to the database with a tint data footprint.
  4. I cannot understate how awesome #3 is !

typeof() – lifesaving debugger tool

OK so maybe life saving is a little stretch but in this article I will illustrate an occurrence of where using type of() helped solve a real world problem.

The Problem

I wanted to display a data source within a repeat control – relatively simple situation I guess but my brain was asleep that particular morning. I wanted to display the repeat control value within a computed text control……seemed simple

	<xp:this.data>
		<xp:dominoView var="viewSortOrder" viewName="vwSortOrder"></xp:dominoView>
	</xp:this.data>
<xp:repeat var="repeatSortOrder" id="repeat1" value="#{viewSortOrder}" disableOutputTag="true">
	<xp:text tagName="li" escape="false" disableTheme="true">
		<xp:this.value><![CDATA[#{javascript:var temp=""
		temp=temp+repeatSortOrder.title //here is the repeat
		.......
	</xp:text>
</xp:repeat>

Unfortunately this created an error 500 – one of the most useless errors known to XPages but I knew something was wrong…but what?

The answer

Then to my rescue comes “Super TroyReimer” who is of course one of the smartest people I know and he says “oo I dunno let’s find out”

“Why don’t we start by finding the typeof for the repeatSortOrder”?

“errrrrr ok *shaking head and humoring MrSmartGuy*”

so I ran a quick print to the screen and look what came back?

println(typeof(repeatSortOrder))

ty1

Oh well DUH Marky……

The repeat control in this context is running a notesViewNavigator in the Java code (I knew that) and therefore in the computed context it is returning a notesview entry every time the repeat cycles….

So in that case the solution is not repeatSortOrder.title is it repeatSortOrder.getColumnValue(‘title’)

	<xp:this.data>
		<xp:dominoView var="viewSortOrder" viewName="vwSortOrder"></xp:dominoView>
	</xp:this.data>
<xp:repeat var="repeatSortOrder" id="repeat1" value="#{viewSortOrder}" disableOutputTag="true">
	<xp:text tagName="li" escape="false" disableTheme="true">
		<xp:this.value><![CDATA[#{javascript:var temp=""
		temp=temp+repeatSortOrder.getColumnValue('title') //here is the repeat
		.......
	</xp:text>
</xp:repeat>

and that works just fine

Conclusion

Troy Reimer is a very smart person

We all have brain farts and I hope you are as lucky to work with some really smart people like I am

typeof() is a very smart way of figuring out why your object is not what you think it is in SSJS