Oh my god. It's full of code!

Salesforce – Pushing Custom Buttons to the Limit With jQuery and Apex

This might fall more in the realm of tech demo than really useful, but I think it awesome. So many of us are aware of custom buttons for Salesforce objects. They allow you to open custom links, go to visualforce pages, and even run custom javascript. That last part is what we are interested in. Sometimes you want to give your users more functionality without having to create a whole visualforce page. We used to have sControls, but then they took those away. It turns out, if you are clever custom buttons can do just about anything you want. The other great thing is that you can call Apex methods from them.

As readers of my blog may also know, I freaking love jQuery. It’s just great. So how can we combine these awesome two things into something even better? Combine jQuery and Apex through the user interface for epic sweetness. First hard part is actually getting jQuery loaded in the dom, and making sure it’s ready. Second tricky part is calling your Apex method without having it become blocking and holding up the jQuery processing. In my example I want to display a nice dialog to the user while the apex code runs. It can take a while so I wanted the dialog to show up immediately and update the message when the apex call was complete. In the end, this is what I came up with.

//Get the Salesforce apex connection libraries
{!REQUIRESCRIPT("/soap/ajax/10.0/connection.js")}
{!REQUIRESCRIPT("/soap/ajax/10.0/apex.js")}

var interval;

//The main function that does all the work
function appendScript()
{
    //We want to use jQuery as well as the UI elements, so first lets load the stylesheet by injecting it into the dom.
    var head= document.getElementsByTagName('head')[0];
    var v_css  = document.createElement('link');
    v_css.rel = 'stylesheet'
    v_css.type = 'text/css';
    v_css.href = 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/themes/redmond/jquery-ui.css';
    head.appendChild(v_css);

    //Okay, now we need the core jQuery library, lets fetch that and inject it into the dom as well
    var script= document.createElement('script');
    script.type= 'text/javascript';
    script.src= 'https://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js';
    head.appendChild(script);
    
    //And of course we need the jQuery UI elements
    var scriptUI = document.createElement('script');
    scriptUI.type = 'text/javascript';
    scriptUI.src = 'https://ajax.googleapis.com/ajax/libs/jqueryui/1.8.16/jquery-ui.js';   
    head.appendChild(scriptUI);

    
    //It takes a second to load, so put in a delay (we don't want to try and reference the         
    //script before it is actually loaded. We store the interval in the global variable, and set up
    //this interval dealio. This will keep running until jQuery has been found to be loaded and then
    //clears the interval so it doesn't keep running.

    interval=self.setInterval(function(){
                                       
        //Check to see if jQuery has loaded                           
        if(jQuery)
        {
            //if jQuery has loaded, clear the interval
            window.clearInterval(interval);
            
            //create a div in the body which we will use for our dialog.
            $(document.getElementsByTagName('body')[0]).append("<div id=infoNotice title='Creating Checks'>Creating Checks Please Wait...<div id='infoNoticeResult'>Just chill, its working.</div></div>");    
            
            //register our newly created div as a dialog
            $( "#infoNotice" ).dialog();   
            
            //setTimeout is non blocking (basically async) so lets put our apex call in a timeout so it doesn't
            //stop our dialog from showing.
            setTimeout(function(){
                                
                //Call out to our apex webservice that does the work. Store the results in the callResult variable                
                var callResult = sforce.apex.execute("campaignClasses","createChecksBatch",{campaignId:"{!Campaign.Id}"});
                
                //Write the result of the call into the div. Apex webservices return arrays, even if the return type
                //is set to string. So just reference the 0th position element to get the string that was returned 
                //to report to the user.
                $( "#infoNoticeResult" ).text(callResult[0]);
            },10);
        }
    }, 300);    
}
appendScript();

If you want to try and copy and paste this, create a custom button on your desired object. Set it to onclick javascript. Add it to your objects page layout. Of course in the apex call change the campaignClasses to your class, and createChecksBatch to your method name.

Like I said, this is just more proof of concept and something to build on. This shows you how you can leverage jQuery in your standard object pages, as well as Apex to build some pretty awesome stuff without having to start trying to inject visualforce pages.

11 responses

  1. Pingback: Salesforce Call Apex Code From Hompeage Component « I Write Crappy Code

  2. Fitz

    God Bless us…everyone! I’ve been trying to shove jQuery down SF’s DOM’s throat for weeks now…took me that long to find this article. Thanks!!!

    December 9, 2011 at 4:36 pm

  3. Glad to have been a help! Hope it goes well.

    December 9, 2011 at 4:37 pm

  4. Fitz

    This was EXACTLY what I needed! Finally got this goddamn project done. I needed to do some SF-side encryption of a query-string load going cross-domain. The host required that the encrypted-load expire after a few seconds, so it needed to be encrypted at link click time. I’d already set up a page to do this work, but wanted a custom-button solution for related-lists. Nearly lost my mind trying to figure out ways of loading jQuery BEFORE the SF stuff…this worked great. Very elegant too…BRAVO!

    December 9, 2011 at 11:32 pm

  5. Sweet deal man. Glad it worked out! If you are feeling generous, the Salesforce MVP nominations are open now 😉

    December 10, 2011 at 12:47 am

  6. Anonymous

    another note to add is to use the https links to the jQuery libraries, otherwise the browser may block the retrieval due to insecure connection

    August 10, 2012 at 12:17 am

  7. I want to put a close button on this in the Div section but I am not finding the right element to do the window.close() any suggestions?

    July 25, 2013 at 9:56 pm

  8. antony

    Can we use this kind of stuff to prepolate some standard field? @_@

    December 19, 2013 at 5:27 pm

    • Sure, you just have to find the ID of the field (use dev tools > inspect element) and write the desired value to the field using something like $(‘#fieldID’).val(‘My new value’);

      December 19, 2013 at 5:32 pm

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