How to add icons to individual items in a Select2 multi-value field

Select2 is one of the best user interface enhancers I have come across – if you do not know what it is then you need to go play with it.

It transforms SELECT boxes into dynamic, stunning, interactive UI elements and allows for all sorts of customizations and developer fun.

What I want to be able to do is select items from different categories within the select2 box and then add an icon displaying to the user which category they came from. In this article I will show how.

Example

I want to take this

s3

turn it into this with a type aheads2

And when a user selects the items – make this based on the category selected

s2

And it is really pretty simple and straightforward.

The Code

We start with our select box

<select style="width:500px" id="vehicle" multiple="multiple">
<optgroup label="Cars">
	<option class="car">Honda</option>
	<option class="car">Toyota</option>
	<option class="car">Ford</option>
	<option class="car">GM</option>
</optgroup>
<optgroup label="Bikes">
	<option class="bike">Harley Davidson</option>
	<option class="bike">Kawasaki</option>
	<option class="bike">Aprilia</option>
	<option class="bike">Ducati</option>
</optgroup>
</select>

and then we add our select2 code

$("#vehicle").select2().on("change", function(e) {
	if (e.added) {
		var icon = ""
		$('.select2-search-choice DIV').filter(function() {
		    icon = '<img src="images/'+e.added.css+'.png"/>&nbsp;';
		    return $(this).text() == e.added.id;
		}).prepend(icon);
      }
})

So what this does is:

  • select the #vehicle DOM element
  • turn it into a Select2 plugin control
  • When the control is changed and if an element is added
  • Find the DIV which has been created to display the new item
    • We use filter based on the newly added.id to make sure we only get the one just created
  • create the HTML for the appropriate icon based on the class of the selected item
  • prepend that icon HTML inside of the DIV containing the newly selected option

Conclusion

I have barely scratched the surface of what is possible with Select2. But I hope that you can see with only 9 lines of code we have significantly improved a user experience 🙂

I love Select2 and the options are endless

Enjoy 🙂

jQuery in XPages #20 – NProgress – YouTube-like slim progress bar

In this article I will describe how to implement and use the jQuery NProgress nano scrollbar plugin

Demonstration

The XPages integration of NProgress is demonstrated here

Download

The demonstration database can be downloaded from the link above or from here

NProgress

Introduction

Since Youtube.com added their nano scroll bar at the top of the page there have been a flurry of different jQuery plugins which mimic the nano progress bar at the top of the screen.

np1

The silly thing is that the progress bar itself does nothing useful.

  • It does not
    • Indicate any meaningful progress on the download of the AJAX or page
    • Give any indication of the likelyhood of page download completion
  • It does
    • Give the user a false sense of something happening on the page
    • Provide a nice User Experience for very little overhead and effort on the part of the developer

Using NProgress you can very quickly and easily add this capability to your website for only a very small overhead to the size of your application.

Adding NProgress to your XPages

  • Go to the NProgress site and download the file from the github site linked on the page
  • Drag and drop the contents of the zip file into your WebContents folder
  • Create a sample page with the following
 <link href='nprogress/support/style.css' rel='stylesheet' />
  <link href='nprogress/nprogress.css' rel='stylesheet' />

<xp:this.resources>
	<xp:headTag tagName="script">
		<xp:this.attributes>
			<xp:parameter name="type" value="text/javascript" />
			<xp:parameter name="src" value="js/jquery.js" />
		</xp:this.attributes>
	</xp:headTag>
</xp:this.resources>

<xp:this.resources>
	<xp:headTag tagName="script">
		<xp:this.attributes>
			<xp:parameter name="type" value="text/javascript" />
			<xp:parameter name="src" value="nprogress/nprogress.js" />
		</xp:this.attributes>
	</xp:headTag>
</xp:this.resources>

The reason we add this to our XPage in the manner above is because nprogress uses AMD as a possible loader (to integrate with require.js) and because of that Dojo 1.8 (on an R9 server) breaks it.

On my demo page I have loaded a viewPanel with 1300 documents in it – I cannot show you more because I do not want a large database on my host’s site but rest assured if you run this up to a 5000 row viewPanel the effect is better because the refresh is slower.

np2

On the demo I have included the main example from the NProgress site and you can see that there are a number of methods for starting and manipulating the progress bar. I use start because it very nicely randomly increments itself to give that illusion of progress.

On the XPage I have a button which refreshes the view Panel – and in the client script as the button is pushed I start the NProgress. In the onComplete of the refresh I end NProgress and really it is as simple as that

<xp:button value="Reload  viewPanel" id="button1" styleClass="clickMe btn btn-warning">
	<xp:eventHandler event="onclick" submit="true" refreshMode="partial" refreshId="viewwrapper"
		onComplete="NProgress.done()">
		<xp:this.script><![CDATA[
			NProgress.start()
		]]></xp:this.script>
	</xp:eventHandler>
</xp:button>

I would suggest that if you are able to integrate with Tony McGuckin’s excellent XSnippet for intercepting dojo io events you could create an automated NProgress bar should you so chose.

Conclusion

As web developers we have used spinners in our application for quite a number of years – this is a new twist on that concept and seems to be getting very good reviews from users. Consider integrating it into your applications.

Using jQuery to remove Dojo CSS from an XPage

I am currently working on a customer application which is oneuiv2.1 themed and I wanted to create a simple jQuery Mobile site. the dojo css was really messing up the styling and just for interest I wanted to see if I could programmatically remove the dojo css from the page client side

The application has the property checked to use runtime optimized JavaScript and CSS. This combines all the dojo css files nicely into one link.

do1

Using a jQuery selector I can get a handle on that <LINK> as follows

$('link[href*="dojo.css"]') //select all LINK objects where the href contains dojo.css

do2

Once I have that I can just remove the element from the DOM like this

$('link[href*="dojo.css"]').remove()

Unfortunately I cannot show you what this does my customer’s site to make it look all pretty and jQueryMobile like, but I can show you how it blows up a oneui site and you can take it from me this fixed my problem.

Just add the above code in a *SCRIPT* tag within your XPage and it will remove the dojo style before it is rendered to the end user – thus they will never know.

http://xpages.info/xpageshome.nsf/Demos.xsp

Before

do3

After

do4

 

Caveat

Yeah I realize this means the CSS file(s) are downloaded and then removed and I am sure there are more elegant ways to handle the issue server-side.

This was an exercise in learning that jQuery can be used to remove entire CSS DOM objects 🙂

Remove all classes using dojo and jQuery

One of last week’s challenges on the side was to take this Connections wiki page and make it readable on a small screen – if you drag the right hand side over to the left you will see that the right navigation menu overlays the non-wrapping text. The main section is forced to a 980px width !

http://www-10.lotus.com/ldd/lcwiki.nsf/dx/Best_Practices__Troubleshooting_Lotus_Connections_3.0#Traces

A very brute force approach to this is to remove all the classes from all the elements on the page

In jQuery you would do this:

$('*').removeClass()

in dojo (which the page is written in) it takes slightly longer

dojo.forEach(dojo.query('*'), function(item, i){
    item.className=""
})

It would be relatively simple to turn this into a bookmarklet to run for yourself

Here is a bookmarklet you can add to do it for you – this will also work on other IBM wiki pages

Create any link on your bookmark bar and then edit it. Copy and paste the following as your URL

javascript: dojo.forEach(dojo.query(‘*’), function(item, i){ item.className=”; })

b1

When you go to the wiki page click the bookmarklet and all classes will be removed – this is only work on pages which have dojo on them already (which IBM documentation does).

Future-proofing yourself.

The other day I got an interesting comment on an old blog post of mine and I felt like it really deserved a separate post in response rather than being lost in the comments. This is a personal assessment of my skills and the need to future proof myself – it is not a sermon – just personal musings which will hopefully inspire.

The Comment

I have copied the comment here for context.

The past several months, I’ve been working on many Notes client applications, but now we’re ready for a big web based application! So, back to jQuery (YAY!) and some dojo (boo!).
Outside of the XPages world, it seems that jQuery is overtaking everyone else. In fact, I heard that the next version of javascript is taking elements of jQuery! I remember there were Mootools, Scriptaculous, Prototype and TONS of others over the years! Just check the stats of how many Stackoverflow questions there have been for various js librairies: http://stackoverflow.com/tags. It’s not even close! So, for the sake of argument, what if dojo shuts down within 3-5 years, and only Xpages are using them. Then what?

From the outside world, it just seems that jQuery is the better long term decision. Any thoughts?

The Answer(s)

So a couple of things to address directly from the comment:

  1. IBM is a significant contributor to Dojo and has been for many years – I think it is unlikely to “shut down”
  2. jQuery may be “the world’s most popular JavaScript library“, but who’s to say it will be that in 3-5 years? In terms of the internet that is a lifetime away.
  3. JavaScript is an evolving language and of course it will take into consideration any techniques and desires that the development community wants/needs. IFRAME, AJAX and parts of the HTML Spec which we take for granted today were invented as IE only tools which make it into the spec (yeah Microsoft was really groundbreaking in some senses)
  4. I do not agree that jQuery is a better long term decision – I think it is a much better “today” decision and probably at least the next couple of years decision – but what is “long term” anyway? 🙂
  5. Learning the fundamentals of JavaScript I believe is the best long term decision and then the actual library becomes much less of a conversation.

So What?

So I really take the original question as one about future-proofing yourself rather than XPages specifically. For those of you who have already taken the plunge to XPages you have already “evolved” your skillset and you have almost certainly learned new skills (like them or not). Really that is what is important is the adaptability of your skillset – not what should I learn today and what should I be ready to learn tomorrow.

So having learned XPages, what is the hardest thing you have had to learn? For me it is all of the server side controls and the JSF component model. It still causes me mental heartache today and probably always will. I am sure it is obvious to anyone who regularly reads my posts, I am much much happier in the user interface, Client Side JavaScript is my thing, it always will be. I am content that that decision will not harm my future work prospects.

Future Proofing Marky

So for me future proofing myself happened the day I realized that I had been “programming JavaScript” for over 10 years but I had not been a “JavaScript developer” for any of it. If these terms are not familiar to you then you are also not a JavaScript developer: closures. object literals, prototypal inheritance, callback functions, IIFE.

So I set out to learn……and jQuery helped me do that. But……..

There are people who believe that jQuery is an unnecessary safety blanket used by people who do not really understand the language. They also believe that jQuery encourages people to be able to program websites using plugins while they understand very little of the underlying concepts. To that I say *crap*. I do not understand how C and C++ work but I use an operating system and developer tools written in those languages – is anyone fussing about not knowing that? I think not.

My point is, that learning jQuery itself will not teach you to be a JavaScript developer – but it most certainly can help.

  1. The code is free and easy to read – the non-minified version is well documented, easy to read and well laid out
  2. There are many blog posts on how does jQuery work (this is the funniest)
  3. You owe it to yourself to better understand web technology. It is not going away. You may as well start using the tools and understand them as you go along.

I am not saying you must learn JavaScript or you will fail as a developer – far from it. But I will challenge anyone who thinks they are a web developer and is not a JavaScript developer then you are fooling yourself.

JavaScript is not only restricted to web development. As we all see in XPages it is also a server side language and in node.js the fastest growing server side technology for web application development.

Conclusion

So for Marky, JavaScript is the obvious choice. It is not Java, it never will be for me, and I am happy with that decision. I am also convinced that my action will determine my fate. I will not wait for fate to tell me what to learn after my job no longer exists.

The conversation shouldn’t be about what is the best library to use for the future but what skillset do you need to be able to adapt. If you build web sites then JavaScript has to be the way to go.

Web technology moves on a <2 year cycle – welcome to the future of constant re-invention of your skillset if you want to remain relevant.

For your own sake, make yourself better and more flexible – you have no one else to blame if you don’t and the worst happens.

For the record

If XPages is no longer in 3 years what will you do? 2.5 years from now will not be the time to figure that out.

I have no evidence or reason to believe XPages will be going away any time soon 🙂

Dojo is a fantastic JavaScript library. It was never designed to make sexy websites, it was created as a framework for application design. XPages is a fantastic example of how to use Dojo to build a framework – well done IBM.

jQuery is not intended to build “websites”. It is intended to help in the development of websites and simplify the developer experience through standardized functions and removal of browser dependencies.

Ember.js, Angular.js, backbone.js and many others are the new, modern “today” libraries for architecting websites. MEAN is the new LAMP stack and if that all means nothing to you – you should at least do yourself the service of some reading.

Sheer coincidence that I saw this from Tim Tripcony today – same deal – different perspective – same conclusion (metaphorically speaking) 🙂

 

 

 

 

 

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

 

 

XPages ND9 (Dojo 1.8) does not work with other AMD loaders (and the work around)

Today I took a new jQuery plugin that I was playing with from an R8.5.3 environment where it worked, to an R9 environment and it failed – I figured it had something to do with something I had been reading about over the last month and in fixing my problem this lead to a more serious realization that I KNOW other people are also going to come across.

Background

A brief scan of the last month’s discussions on Xpages and jQuery Mobile 1.3 reveals a number of posts started by Dave Leedy regarding the use of IBM Notes Domino 9 and jQuery Mobile 1.3

http://notesin9.com/index.php/2013/04/20/jquery-mobile-seems-incompatible-with-xpages-in-domino-9-0

http://hasselba.ch/blog/?p=1216

http://stackoverflow.com/questions/16058039/jquery-mobile-in-xpages-passing-parameters

http://www.eknori.de/2013-04-21/followup-jquery-mobile-seems-incompatible-with-xpages-in-domino-9-0/

What’s going on?

I saw the following Tip from Sven Hasselbach (very smart man!) on Dave Leedy’s blog post

Looks like an AMD loader problem with Dojo & JQM. I have tried out to disable the Factory scan in a test page and this worked for me. To do this I have added the following parameters in the xsp.properties:

xsp.client.script.dojo.djConfig=dojo-amd-factory-scan: false

Maybe this can help you with your problems in ND9.

This lead me to this bug report

https://bugs.dojotoolkit.org/ticket/15616

make dojo work with other AMD loaders

Which then lead me to the realization that this is a bigger issue than just JQM 1.3 and I solved my problem and here is how.

Solution (ND9)

Within the Package Explorer  (Window—open perspective –> xpages) in the WebContent folder for your database you will find the xsp.properties file (as described http://heidloff.net/home.nsf/dx/06172011015521AMNHE8Y7.htm)

xsp1

Click to open the Source Tab

and enter the following

xsp.client.script.dojo.djConfig=dojo-amd-factory-scan: false

And Save – that’s it

Result

If you look at the source code of the created XPage you will see that the new parameter has been added to the script tab creating the dojo.js as a djConfig property

xsp3

doing a quick search explains what this property does

http://dojotoolkit.org/documentation/tutorials/1.8/dojo_config/

“For example, we could disable the amd factory scan (scanning the module for CommonJS require(module) statements to load as deps) with…”

Not only does that solve the problem with jQuery Mobile, it also solved my problem with the jQuery Table plugin which I wanted to use, which used require.js to load the jQuery dataTable plugin.

GENIUS

thank you Sven Hasselbach (again!)