This article is going to walk through the process of converting a business rule originally coded for Internet Explorer to one that uses the jQuery javascript library to work in all browsers.
This article uses as its base the business rule originally discussed in the article "Controlling Buttons using Client Side code" on the Hints, Tips and Tricks blog.
The business rule states that the 'Convert to Opportunity' button on the Lead Summary screen should only be available to the user that is the Leads assigned manager. If the lead belongs to the user Trish Simmons, then even though a user like Susan Maye can have general edit rights for the Lead they are not authorised to convert it into an opportunity.
Back in version of Sage CRM prior to Sage CRM v7.1 SP2 the only browser that we need to worry about was Internet Explorer.
The rule above could be implemented using code like this:
Example 1: Plain Old Javascript, Internet Explorer Only Code
[code language="javascript"]
<SCRIPT>
//This works only in Internet Explorer
window.attachEvent("onload", hideButton)
function hideButton()
{
var arrayTags = document.getElementsByTagName("A");
var re = new RegExp(CurrentUser.user_displayname,"i")
if (!_Datalead_assigneduserid.innerText.match(re))
{
for(i=0;i<arrayTags.length;i++)
{
if(arrayTags[i].href.search(/ValidateCompanyEntry/i)>-1)
{
arrayTags[i].style.visibility = hidden;
}
}
}
}
</SCRIPT>
[/code]
If we want it to be triggered in Chrome and Safari then we would need to change it to the following code.
Example 2: Plain Old Javascript, Cross Browser Code
[code language="javascript"]
<SCRIPT>
if (window.addEventListener)
{
//firefox way of binding an event
window.addEventListener("load", hideButton, false)
}
else
if (window.attachEvent)
{
//IE exclusive method for binding an event
window.attachEvent("onload", hideButton)
}
function hideButton()
{
var arrayTags = document.getElementsByTagName("A");
var re = new RegExp(CurrentUser.user_displayname,"i")
if (!_Datalead_assigneduserid.innerText.match(re))
{
for(i=0;i<arrayTags.length;i++)
{
if(arrayTags[i].href.search(/ValidateCompanyEntry/i)>-1)
{
arrayTags[i].style.visibility = hidden;
}
}
}
}
</SCRIPT>
[/code]
The code in the section above uses the addEventListener() method as a test to see whether the browser running the code is Internet Explorer or not. This example shows very clearly that when we are coding for business rules in Sage CRM's screens we are faced with incompatibilities between the different browsers.
jQuery as a library provides us with a simpler way of writing the so that we do not have to consider this ourselves. The jQuery library defines a global function to select the objects with which we wish to work. The function is called jQuery() but this is commonly referenced using the symbol $.
Where we have previously written
[code language="javascript"]
var myTags = document.getElementsByTagName("TD");
[/code]
we can now write
[code language="javascript"]
var myTags = $("TD");
[/code]
The $ function would return the set of "TD" tags as a jQuery object.
Common ways of using the $() function are
1) Pass a CSS selector string.
e.g.
[code language="javascript"]
$("TD")
[/code]
or
[code language="javascript"]
$("span.viewboxcaption")
[/code]
or
[code language="javascript"]
$("input",document.forms[0])
[/code]
2) Pass an Element, Document or Window object.
e.g.
[code language="javascript"]
$(document), or $("#_Datacomp_name")
[/code]
3) Pass a string containing HTML tags.
e.g.
[code language="javascript"]
$("<input type='checkbox'>")
[/code]
or
[code language="javascript"]
$("<input/>",
{ type:checkbox}
[/code]
4) Pass a function to the $() method.
Possibly the most useful for us to use in Sage CRM is to use an anonymous function that will be invoked when the whole document has loaded.
e.g.
[code language="javascript"]
$(function(){
//Called when document is loaded;
//do some jQuery here;
});
[/code]
Note: jQuery fires the functions registered through $() when the "DOMContentLoaded" event occurs. DOMContentLoaded has been added to the HTML 5 Draft Specification. "DOMContentLoaded" has been implemented in the Webkit rendering engine so is supported by all the versions of Google Chrome and Safari. DOMContentLoaded is also implemented in Internet Explorer and Firefox.
This business rule that we are working on can first simplified by using an anonymous function to run when the page loads.
Example 3: Using jQuery Anonymous Function on DOMContentLoaded for Cross Browser Code
[code language="javascript"]
<script>
$(function(){
//Called when document is loaded;
//do some jQuery here;
var arrayTags = document.getElementsByTagName("A");
var re = new RegExp(CurrentUser.user_displayname,"i")
if (!_Datalead_assigneduserid.innerText.match(re))
{
for(i=0;i<arrayTags.length;i++)
{
if(arrayTags[i].href.search(/ValidateCompanyEntry/i)>-1)
{
arrayTags[i].style.visibility = "hidden";
}
}
}
});
</script>
[/code]
Further simplification can be made around the selection of the hyperlinks that need changing. With jQuery selectors you can find elements based on their id, classes, types, attributes, values of attributes and much more. It's based on the existing CSS Selectors, and in addition, it has some own custom selectors.
Much of the code in Example 3 is concerned with finding all the <A> tags with href attributes that contain the text 'ValidateCompanyEntry'. These are the hyperlinks to the 'Convert to Opportunity' behaviour.
We could replace the base behaviour of the line of code
[code language="javascript"]
var arrayTags = document.getElementsByTagName("A");
[/code]
with
[code language="javascript"]
var jTags = $("A");
[/code]
The object returned by the code
[code language="javascript"]
var jTags = $("A");
[/code]
is array-like. It will have a length property like an array and the set of objects within it can be referenced using the array notation e.g. jTags[1] etc.
jQuery has methods to work with the objects. I can reference the length either using jTags.length or jTags.size()
But the jQuery selector can do much of the work as explained here: http://www.w3schools.com/jquery/jquery_selectors.asp
For example
[code language="javascript"]
$("TD.ButtonItem")
[/code]
would select all of the TD tags of the CSS class 'ButtonItem'. And
[code language="javascript"]
$("A.[href]")
[/code]
would select all the A tags which have hyperlinks. And this selection can be extended further to look for the text 'ValidateCompanyEntry' used in the hyperlink.
[code language="javascript"]
var jTags = $("A[href*='ValidateCompanyEntry']");
[/code]
Note: The '*=' is the symbol for 'contains'.
Another use of the Selector can be one that uses the ID of an element.
[code language="javascript"]
var jField =$("#_Datalead_assigneduserid");
[/code]
This can be further filtered to search whether the element contains a string.
[code language="javascript"]
var jField =$("#_Datalead_assigneduserid:contains('Fred')");
[/code]
The ":contains" uses the text parameter to matches those elements that contain the string passed. We can use this to simplify the test in the business rule to see if the Leads belongs to the current logged on user or not.
As I mentioned previously the jQuery object returned by the selection is an array-like set of objects. A jQuery object is always returned but if nothing matches the selector then the length will be zero. This set of objects representing the found hyperlinks would need to be worked through to hide the links. jQuery behaves like a namespace and provides a number of utility functions beneath it. An example is $.each() which can used to iterate through the resultset.
Example 4: The finished jQuery version of the business rule.
[code language="javascript"]
<script>
$(function()
{
var strSelector = "#_Datalead_assigneduserid:contains('"+CurrentUser.user_displayname+"')"
if ($(strSelector).length==0)
{
var jTags = $("A[href*='ValidateCompanyEntry']");
jTags.each(function()
{
$(this).hide();
})
}
});
</script>
[/code]
The behaviour called by the each() method calls a function that calls back to the items in the result setting the style of each item.