Home > Visualforce, jQuery > Add Slider to a Visualforce Page with jQuery

Add Slider to a Visualforce Page with jQuery

February 16th, 2010

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;        
    }
}
Categories: Visualforce, jQuery
  1. February 16th, 2010 at 11:05 | #1

    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(){});

  2. February 16th, 2010 at 11:29 | #2

    It just doesn’t work for me.

    This doesn’t work:

    <apex:page standardController="Opportunity" id="page" >
        <apex:includeScript value="{!URLFOR($Resource.jquery, 'js/jquery-1.3.2.min.js')}"/>
     
        <script type="text/javascript">    
            jQuery(document).ready(function(){
                jQuery(#"{!$Component.page.form.name}").click(function(){alert('hi');});
            });
        </script>
     
        <apex:form id="form">
            <apex:inputField value="{!Opportunity.Name}" id="name"/>
        </apex:form>
    </apex:page>

    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.

  3. February 16th, 2010 at 11:45 | #4

    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!

  4. February 16th, 2010 at 11:48 | #5

    My apex example disappeared, but looked something like

    apex:inputField value=”{!Demo__c.Budget_Low__c}” id=”budgetLow” styleClass=”budgetLow”

  5. Jason
    February 16th, 2010 at 11:53 | #6

    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.

  6. February 16th, 2010 at 11:57 | #7

    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?

    
    				
  7. February 16th, 2010 at 11:59 | #8

    (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" /]

  8. February 16th, 2010 at 12:05 | #9

    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.

  9. February 16th, 2010 at 12:29 | #10

    Please vote up my idea on the AppExchange to support HTML5 custom data attributes in Visualforce markup. http://bit.ly/dlHAdl

  10. Richard
    February 16th, 2010 at 12:46 | #11

    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();

  11. Richard
    February 16th, 2010 at 12:47 | #12

    Oh and wonderful post as always Jason.

  12. February 16th, 2010 at 13:08 | #13

    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

  13. February 16th, 2010 at 13:31 | #14

    Very cool! I like yours better. ;) Congrats!

  14. Mom
    February 16th, 2010 at 15:57 | #15

    Wow Jason, you have come along way since learning the alphabet! :)

  15. February 16th, 2010 at 16:08 | #16

    @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.

  16. February 17th, 2010 at 03:42 | #17

    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.