Skip navigation

Tag Archives: javascript

Today I was creating some new Salesforce Permission Sets for objects with hundreds of fields, where the PermissionSet needed access to just about every field on the object. If you’ve ever been in this scenario, you know what this means — get ready to manually check hundreds of checkboxes!

LotsAndLotsOfFields

Being a developer, any time you have to do something repetitive, you start going nuts — there’s got to be a way to do this faster! 

In this case, the solution seemed pretty straightforward: just use jQuery to go find all checkboxes, and check them! From Chrome, Firefox, or Safari, just do a right-click, select “Inspect Element”, and then enter this one easy line of code:

jQueryInConsole

That line of code, again, is:

jQuery('input[type="checkbox"]').prop('checked',true);

This should work great, but there’s just one problem — Salesforce standard pages don’t usually include jQuery!

This leaves us with two options. One, we can resort to native DOM manipulation methods. If you are very comfortable with native DOM methods, then this is the way to go. Here’s the code:


// document.querySelectorAll returns a NodeList,
// so in order to leverage the ECMAScript 5 "forEach" method of Arrays,
// we'll convert our NodeList to an Array using slice

Array.prototype.slice.call(document.querySelectorAll('input[type="checkbox"]')).forEach(function(e){e.setAttribute("checked","checked");});

For a comparison of the complexity of these two approaches, take a look at this Gist.

If the DOM works for you, you’re done! However, if you don’t think you can remember how to code this every time, and/or prefer jQuery, never fear — there’s a really easy way to inject jQuery into any page you may be visiting: the jQuerify Chrome Extension. To get it, just go to the Chrome Extensions library and search for “jQuerify”:

jQueryify

Once you’ve added this extension, you now get a handy little button at the top right corner of Chrome, that lets you, with one-click, embed jQuery into any page, including your Salesforce PermissionSet / Profile editor!

ButtonOnPage

Now, you can confidently run the aforementioned line of jQuery code, and ALL Checkboxes will be automatically checked! Yahoo!

AllChecked

Whichever method you use, DOM Native or jQuery, all it takes to repeat this magic when you move to the next Object with hundreds of fields is to go back to the Developer Console, hit the Up Arrow key on your keyboard, and voila, you’ve got your last-run script. Hit return, and the magic repeats!

Use Firefox and Firebug instead of Chrome? There’s an identical plugin for Firebug, called Firequery.

To help foster an ongoing conversation among Salesforce ISV and OEM partners — aka developers of Salesforce AppExchange apps — I started this discussion on the Salesforce ISV Partners LinkedIn group, which I encourage fellow ISV’s/OEM’s to join:

Let’s pool our thoughts – best practices for Salesforce ISV/OEM app development

One of the best practices I brought up was the need to properly “protect” or “sandbox” your application’s references to external JavaScript libraries within complex “mash-up” pages that include JavaScript code written by various other ISV’s / OEM’s / consultants / developers, as well as underlying Salesforce.com JavaScript code.

These days, more and more apps being developed on the Salesforce Platform rely heavily on external JavaScript libraries such as jQuery, jQuery UI, jQuery Mobile, ExtJS, Sencha Touch, KnockoutJS, AngularJS, Backbone, MustacheJS, Underscore, JSONSelect, etc. Leveraging these libraries is definitely a best practice — don’t reinvent the wheel! As jQuery quips, “write less — do more!” As a Salesforce consultant, I think, this is generally the goal 🙂

Problems emerge, though when multiple ISV’s include different versions of these JavaScript libraries as Global Variables within their Visualforce Pages or Visualforce Components — because whichever version is loaded last will, by default, overwrite the earlier version. This makes it very difficult to mash-up / integrate Visualforce Components or Pages from multiple ISV’s into a single page. When faced with this, a common developer response is to stop using the latest version of the external library and trying to make their code work against the earlier version of the library forcibly included in the page (perhaps by a managed Visualforce Component or embedded Visualforce Page).

Fortunately, there IS a better way to avoid this.

In a nutshell, the solution is: “protect” or “localize” your references to any external libraries, preferably in a JavaScript namespace corresponding to your managed package.

For instance, if your Salesforce application has the namespace “skuid”, you’re already going to probably have various JS Remoting functions available within the “skuid” JavaScript object that Salesforce automatically creates in pages with controllers with JS Remoting methods — and as an ISV, you are ensured of your managed app’s namespace being Salesforce-unique. So this namespace is just about the safest global variable you can use in the Salesforce world (anyone else who messes with it is being very, very naughty)

As a brief side-note, here’s how to ensure that your app’s “namespace global” has been defined before using it:

// Check that our Namespace Global has been defined as already,
// and if not, create it.
skuid || (window.skuid = {});

To protect your external library references, store a unique reference to these libraries within your namespace’s object, e.g. IMMEDIATELY after loading in an external library, such as MustacheJS,

// Load in Mustache -- will be stored as a global,
// thus accessible from window.Mustache
(function(){ /* MustacheJS 0.7.2 */ })()

// Store a protected reference to the MustacheJS library that WE loaded,
// so that we can safely refer to it later.
skuid.Mustache = window.Mustache;

Then, even if some other VF Component or Page loads in a different version of this library later on, you will still have access to the version you loaded (0.7.2)

// (other ISV's code)
window.Mustache = (function(){ /* MustacheJS 0.3.1 */ })()

// THIS code will run safely against 0.7.2!
skuid.Mustache.render('{{FirstName}} {{LastName}}',contactRecord);

// THIS code, however, would run against the latest version loaded in, e.g. 0.3.1,
// and thus FAILS, (since Mustache 0.3.1 has no render() method)
Mustache.render('{{Account.Name}}',contactRecord);

How to avoid having to use global references all the time

Some of you are probably thinking, “Great, now I have to prepend this global namespace all over the place!” Fortunately, with JavaScript, that’s not necessary. By wrapping your code in closures, you can safely keep using your familiar shorthand references to external libraries without worrying about version conflicts.

For instance, say that your application uses jQuery 1.8.2, but other Visualforce Components on the page are using jQuery as old as 1.3.2! (SO ancient… 🙂 What’s a developer to do?

Well, jQuery provides the helpful jQuery.noConflict() method, which allows you to easily obtain a safe reference to a version of jQuery immediately after you load it into your page. So, as an example, in YOUR code, you need to pull in jQuery 1.8.2:

<!-- load jQuery 1.8.3 -->
<script type="text/javascript" src="//ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script><script type="text/javascript">// <![CDATA[
// Get a safe reference to jQuery 1.8.3 var jQuery_1_8_3 = $.noConflict(true);
// ]]></script>

Then, to your horror, another Visualforce Component, that the customer you’re developing for has “got to have” in this same page (and which you don’t want to iframe…), has loaded in jQuery 1.3.2, but not bothered to namespace it!!! Therefore, both of the commonly-used jQuery globals (jQuery and $), now refer to jQuery 1.3.2!

Fortunately, FOR YOU, you’re safe! You got a protected reference to jQuery 1.8.3, and your code can carry on using $ without any issues, as long as you wrap it in a closure:

(function($){

   $('.nx-table').on('click','tr',function(){
       // Add "edit-mode" styles to this table row
       $(this).toggleClass('edit-mode');
   });

// Identify jQuery 1.8.3 as what we are referring to within this closure,
// so that we can carry on with $ as a shorthand reference to jQuery
// and be merry and happy like usual!
})(jQuery_1_8_3);