Websockets in XPages: Improving on the automated partialRefresh interface

In this article I will further discuss how tom improve the user experience of an automated partial Refresh on an user’s XPage. Although these posts were originally about using Bluemix to host the node.js server I kinda feel that the focus has drifted onto websockets more than Bluemix. So in an attempt to make it easier to find I am going to use the Websockets in XPages title moniker for a few posts and then go back to Bluemix🙂

Introduction

In the last article we looked at how to push a automated partialRefresh to a XPage application using websockets. In that article it was noted that the user experience was not ideal because the whole panel refreshed without the user knowing about it. For some apps that is appropriate and for others it may not be. At this point in his career Dave Leedy is impressed he gave someone else and idea and I quote: “wow! that’s fricken awesome!!!”

So, that’s not a great user experience – what if they were doing something at the time?

Yes I was thinking that too! So I believe we can improve the user experience a little and take what Dave suggested and tweak it a little. Now where have a seen something which let’s the user know there is new data changes but doesn’t refresh the page without their action……….

b4

oh yeah that.

Instead of refreshing the control automatically, we will make the message create a “refresh” icon on the page which the user can then update at their leisure.

b5

The modified code is all in what happens when the page receives the refresh socket message. I added a jQuery rotate function just for some added “je ne sais quoi“. In the function we can see that when the refresh event is detected by the socket code the refreshControl function is called. This in turn makes the hidden refreshIcon visible, adds an onClick event and then rotates it. The onClick event performed the partialRefreshGet as we saw in the previous example turning the page briefly grey. We then hide the icon and remove the click event (to avoid piling on multiple events as the page gets continually refreshed)

 

 // Function to add a message to the page
  var refreshControl = function(data) {

	  $('.refreshIcon')
	  	.css({display: 'block'})
	  	.on('click', function(){
	  	   var temp = $('[id*='+data.refreshId+']').css({background: '#CCCCCC', color: 'white'}).attr('id')
		   XSP.partialRefreshGet(temp, {})
		   $(this).css({display: 'none'}).off('click')
	  	})
	  	.rotate({
	      angle:0,
	      animateTo:360,
	      easing: function (x,t,b,c,d){        // t: current time, b: begInnIng value, c: change In value, d: duration
	          return c*(t/d)+b;
	      }
	   })
  };

  // When a refresh message is received from the server
  // action it
  socket.on('refresh', function(data) { refreshControl(data); });

The following video quickly demonstrates the new capability.

Conclusion

In this brief article we concentrated on how to improve a user experience by notifying them that changes were pending and then allowing them to determine when the changes were made.

I still don’t think this is as optimal as I would like but you get the idea. As I said a long time ago – the more DOM you are reloading the worse the user experience. With a viewPanel we are kinda limited on what we can and cannot refresh. A better option may be to architect the application just the new data and update as appropriate……….

 

6 thoughts on “Websockets in XPages: Improving on the automated partialRefresh interface

  1. ” – the more DOM you are reloading the worse the user experience.”…the idea I’m tinkering with is: all data (JSON) in our app has a unique key, e.g. { somedata: [ { unid: “1”, name: “Bob”}, { unid: “2”, name: “Sue”} ], morestuff: {}}, any changed data received by browser comes out in same structure, let’s say Bob has changed to Robert, we receive { somedata: [ { unid: “1”, name: “Robert”} ], action: “update” }. If you are using Angular\ Ember etc., find the property with unid=”1″ in your model, change it, only that DOM element changes. Or if hand cranking building the DOM\ ui, rebuild the appropriate bit of ui. As a side note, in our current app, when any “actions” are being done, we set a flag on our controller which stops any auto-refreshes, when action finished, reset the flag, auto-refreshes recommence. If something errors etc., the user can just push the “manual refresh” button.

    One architecture question I have not been able to figure out, if the data set being displayed to user is a subset of a larger data set, i.e. page 1 of the “people” view, if a change happens to “Ziggy Zog” by another user, if u have to subscribe to the people channel, does a push get initiated. The stumbling block I have with this is: our app has many concurrent users, changing many documents, each user has different views, some of them paged, each user will have to subscribe to multiple channel(s), else we would just push way to much data up. I need to more research.

    Anyway, following your stuff with great interest, great job!

    • Hey Nick – thanks for the response mate. I am all about the data and not the XPages model controlling the updates – just haven’t gotten to writing about that yet🙂

      So I have actually put some thought to this scenario as you describe above and there are two possibilities as I can see it

      1) You maintain some kind of data map on the server of what each user is looking at and from that determine if they should get an update message (not a good idea IMHO)
      2) Broadcast the data update to all users anyway and let the browser figure it out – effective but inefficient
      3) When there is an update make it a conversation with the browser – which I currently prefer but have not investigated yet

      Broadcast message of just the unique ID and have the browser determine if it wants more information
      If the unid is found on the page and we do want it updating – send back a websockets message requesting the most up to date data for the document
      When the document date comes back update it.

      I think option 3) becomes more viable as the number of concurrent users increases. A small message and then a targeted update provides a more efficient model than just blasting to all users.

      • When sending updates of unique IDs you should think what will happen to the application if a client misses an update (network problems etc.). To prevent this, you could add a hash of the unique IDs to your broadcasts, and the client verifies the hash by recalculating it. As soon as the hashes doesnt match, the client must force an update “manually”.

      • Always insightful !!!

        I am actually thinking in a fully robust system – do you need to have an background conversation between the server and client to verify reception of the message, and resend if no answer received?

        If you were wholly reliant on the push for business critical information you’d have to consider that. But for a “nice to have” screen update probably less critical.

  2. I love your websocket posts. Keep them coming please. Would it be possible to get a copy of your nsf to study websocket more?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s