Add Slider to a Visualforce Page with jQuery
A while back Jeff Douglas posted on his blog how to embed a Flex slider into a visualforce page. This is pretty slick and can be really useful, but I’m not a really a fan of Flex (I’ll post about that later) so today let’s look at doing the same thing a little different.
Instead of using Flex to build the slider I will show you how to do this with javascript. This requires less code and I feel it is easier to implement.
We are going to add a super nifty ultra slick slider with only 16 lines of javascript code.
You can check out the working demo by clicking here..
Below is all of the Visualforce markup, jQuery script, and Apex code. I’ve added most of my notes on what everything does in the comments but feel free to let me know if something isn’t clear or if you have any questions.
The one piece that may jump out at you is why I am using the native javascript getElementbyId method when assigning values to the inputFields. It is because these fields are apex:inputFields and they are given a funky Id that looks like this:
page:form:block:values:budgetHigh
The auto generation of these ids is cool as it prevents duplicate Ids but the semi-colons in the Id wreak havoc on jQuery. Using regular javascript wasn’t that much more work and there were no issues.
<apex:page standardController="Demo__c" id="page" extensions="slider"> <!-- Here we incldued the necessary jquery javascript and css files --> <apex:includeScript value="{!URLFOR($Resource.jquery, 'js/jquery-1.3.2.min.js')}"/> <apex:includeScript value="{!URLFOR($Resource.jquery, 'js/jquery-ui-1.7.2.custom.min.js')}"/> <apex:stylesheet value="{!URLFOR($Resource.jquery, 'css/ui-lightness/jquery-ui-1.7.2.custom.css')}"/> <script type="text/javascript"> //This will load as soon as the page is ready and will setup our slider $(document).ready(function(){ $("#slider-range").slider({ //This line creates a slider on the DIV specified, options are passed arguments, comma separated below range: true, //This give the slider and top and bottom min: 0, //Min value for slider max: 1000, //Max value for slider values: ['{!FlOOR(Demo__c.Budget_Low__c)}', '{!FLOOR(Demo__c.Budget_High__c)}'], //Start values for the slider slide: function(event, ui){ //This function executes every time slider is moved and applies the slider values to the input fields as well as the output below the slider document.getElementById('{!$Component.page.form.block.values.budgetLow}').value = ui.values[0]; document.getElementById('{!$Component.page.form.block.values.budgetHigh}').value = ui.values[1]; $("#amountValue").html('$' + ui.values[0] + 'K - $' + ui.values[1] + 'K'); } }); //This line executes only once right after the page is loaded and after the slider is initialized. It creates the "$273K - $611K" text on load $("#amountValue").html('$' + $("#slider-range").slider("values", 0) + 'K - $' + $("#slider-range").slider("values", 1) + 'K'); }); </script> <apex:form id="form"> <apex:pageBlock mode="edit" id="block"> <apex:pageBlockButtons > <apex:commandButton value="Save" action="{!save}" /> </apex:pageBlockButtons> <apex:pageBlockSection > <apex:outputField value="{!Demo__c.Name}"/> </apex:pageBlockSection> <apex:pageBlockSection title="Budget Info" columns="2"> <apex:pageBlockSectionItem > <apex:outputLabel value="Budget Range"/> <apex:pageBlockSectionItem > <!-- This is where our slider will be --> <div id="slider-range" style="font-size: 90%; margin-top: 0.5em;"></div> <div id="amountValue" style="text-align: center;"></div> </apex:pageBlockSectionItem> </apex:pageBlockSectionItem> </apex:pageBlockSection> <apex:pageBlockSection columns="1" id="values"> <!-- You could make these fields apex:inputHidden and then use only the slider --> <apex:inputField value="{!Demo__c.Budget_Low__c}" id="budgetLow" /> <apex:inputField value="{!Demo__c.Budget_High__c}" id="budgetHigh"/> </apex:pageBlockSection> </apex:pageBlock> </apex:form> </apex:page>
Very simple extension. Simply to override the save and prevent demo from returning to record.
public class slider { Demo__c d; public slider(ApexPages.StandardController controller){ d = (Demo__c)controller.getRecord(); } public void save(){ update d; } }

Pretty slick. Nice job!
What issues did you encounter accessing DOM IDs via JQuery selectors?
Maybe my memory is slipping, but I seem to recall trusting a syntax like this:
jQuery(“{!$Component.thePageBlock.theSection.theSectionItem}’)”).click( function(){});
It just doesn’t work for me.
This doesn’t work:
jQuery(#”{!$Component.page.form.name}”).click(function(){alert(‘hi’);}); gets rendered as:
jQuery(“#page:form:name”).click( function(){alert(‘hi’);});
These semicolons mess everything up. This is noted at the very top of the page here, http://api.jquery.com/category/selectors/ , but you can’t use escaping syntax (\\) with the {!$Component} markup.
Even more information here:
http://docs.jquery.com/Frequently_Asked_Questions#How_do_I_select_an_element_by_an_ID_that_has_characters_used_in_CSS_notation.3F
OK. Now that you mention it, I think I did encounter this and compensated by either selecting by CSS class or just avoiding use of apex: declarative controls.
Maybe something like this?
jQuery(“.budgetLow”).eventHandler();
Less than ideal, I know.
Anyway, great examples. Thanks for sharing!
My apex example disappeared, but looked something like
apex:inputField value=”{!Demo__c.Budget_Low__c}” id=”budgetLow” styleClass=”budgetLow”
Yup, that is one alternative. It definitely works but when you use a class selector there are some things to watch our for. All of the cool browsers (everything but IE) have a native getElementsByClassName so performance is pretty darn good. IE on the other hand has to scan the entire DOM structure which can be slow. With simple pages this probably won’t be too slow or noticeable but it is something to be aware off.
One way to help with the performance issue is use a selector like this:
jQuery(”input .budgetLow”).eventHandler();
There is a native getElementsByTagName for all browsers which is fast and then it will only search these for a matching class name. The only issue with this is that for browsers that support the native getElementsByClassName you are making do more work.
In the end you just need to play around with these options to see what is best.
I’ve started using the HTML5 data attribute for embedding semantics into HTML.
For example
I wonder how VF parses unsupported attributes? Does this work?
(Okay… still struggling with use of pre in comments. re-posted with brackets [])
I’ve started using the HTML5 data attribute for embedding semantics into HTML.
For example
[span id="someElement" data-sforceid="003000000a0D" /]
I wonder how VF parses unsupported attributes? Does this work?
[apex:inputField value=”{!Demo__c.Budget_Low__c}” id=”budgetLow” data-slider-range="low" /]
Sorry about your markup getting stripped. I need to look into that. I don’t think it will let you save unsupported attributes. Wes Nolte was asking about this same thing a few days ago.
Please vote up my idea on the AppExchange to support HTML5 custom data attributes in Visualforce markup. http://bit.ly/dlHAdl
I ran into the same issues when I was using jQuery with vforce so I wrote this quick little javascript method:
function v2j(input) {
return ‘#’+input.replace(/([#;&,\.\+\*~':"!\^\$\[\]\(\)=>\|\/])/g,function(matchString,groupOne){return “\\” + groupOne});
}
example usage: jQuery(v2j(‘{!$Component.thecompid}’)).hide();
Oh and wonderful post as always Jason.
I tried to get something like that working once but couldn’t get it to work:
http://community.salesforce.com/sforce/board/message?board.id=Visualforce&message.id=19344
Very cool! I like yours better.
Congrats!
Wow Jason, you have come along way since learning the alphabet!
@Mom
That’s cool. I never learned how to read. My man Alfred types for me as I dictate. I wish my mom had been supportive of me wanting to learn to read. You have it so good, Jason.
Excellent article and good timing. I’ve been working with a jQuery lib that works best with Ids (my page is MASSIVE and many of list items share a class) and was forced to climb into the topic of visualforce ids and jQuery.. and I think I’ve found a solution (similar to Richard’s in all honesty). Check my blog for deets.