Saturday, January 17, 2015

How to refer VisualForce Elements from jQuery / JavaScript


Normally we use JavaScript with webpages. When we build VisualForce pages, there also we use JavaScript to add functionality. But the way we should refer VisualForce elements from JavaScript is little different. Normally people faces problem while locating the VisualForce elements from JavaScript and sometimes the way people refer VisualForce elements from JavaScript is not the best way to do (which definitely leads to many other problems/issues in future). So in this post, I will go one by one so that we can understand the problem and then we will identify the solutions to overcome that problem. At the end of this post, we will know the best practice. Sounds great, right!!!
I am super excited, so let's start --

Case 1:
Normally a VisualForce page will be converted into HTML by Salesforce. During this conversion process, Salesforce uses a hierarchy to build ID values for page elements. Normally we get the reference of an element by ID in JavaScript in document.getElementById('ID Name'). But if we follow the same in VisualForce page, it will not work. Let's see with an example:

Let's consider the below VisualForce page:
<apex:page id="page">
    <apex:form id="form">
        What is your name?
        <p/>
        <apex:inputText id="name" onfocus="myFunc()"/>
    </apex:form>
    
    <apex:includeScript value="{!URLFOR($Resource.jQuery1_11, '/js/jquery-1.11.2.min.js')}"/>
    <script>
        var j$=jQuery.noConflict();
        function myFunc(){
            var inputTextCatched = document.getElementById('name');
            inputTextCatched.value = "Sudipta Deb";
        }
    </script>
</apex:page>
In the above example  document.getElementById('name');will not work and will return no result. The reason behind is that when Salesforce converts the VisualForce page into HTML, the ID is not setup as 'name', rather it is setup by following the page structure. So it will be setup as - 'page:form:name'. So we need to change the above code as - document.getElementById('page:form:name');The final code is given below -
<apex:page id="page">
    <apex:form id="form">
        What is your name?
        <p/>
        <apex:inputText id="name" onfocus="myFunc()"/>
    </apex:form>
    
    <apex:includeScript value="{!URLFOR($Resource.jQuery1_11, '/js/jquery-1.11.2.min.js')}"/>
    <script>
        var j$=jQuery.noConflict();
        function myFunc(){
            var inputTextCatched = document.getElementById('page:form:name');
            inputTextCatched.value = "Sudipta Deb";
        }
    </script>
</apex:page>
Now we will see the changes as -

Great!!. But this is definitely not the best practice because if you add a new element in the same page in future, the hierarchy will change and hence the selector will break. So we need to find some better option.

Case 2:
Salesforce recommends the use of $Component selector. The syntax is - document.getElementById('{!$Component.<ID Name>}'). This will traverse the hierarchy and provides the ID. But this also having some problem. This selection will only work at the same hierarchy level as the element.

In the below example when the selection happened at the same level, it worked, but it happened at different level, it failed. Below are to examples-

Working Example -
<apex:page id="page">
    <apex:includeScript value="{!URLFOR($Resource.jQuery1_11, '/js/jquery-1.11.2.min.js')}"/>
    <apex:form id="form">
        What is your name?
        <p/>
        <apex:inputText id="name" onfocus="myFunc();"/>
        <script>
            function myFunc(){
                var inputTextCatched = document.getElementById('{!$Component.name}');
                inputTextCatched.value = "Sudipta Deb";
            }
        </script>
    </apex:form>
</apex:page> 
Non working Example -
<apex:page id="page">
    <apex:includeScript value="{!URLFOR($Resource.jQuery1_11, '/js/jquery-1.11.2.min.js')}"/>
    <apex:form id="form">
        What is your name?
        <p/>
        <apex:inputText id="name" onfocus="myFunc();"/>
    </apex:form>
    <script>
        function myFunc(){
            var inputTextCatched = document.getElementById('{!$Component.name}');
            inputTextCatched.value = "Sudipta Deb";
        }
    </script>
</apex:page>    
So this approach is having the drawback - If we need to make selections at various hierarchical levels, then we will end up with fragmented JavaScript throughout the code, which is definitely a good solution.

Case 3:
Here comes the great jQuery. jQuery provides partial ID selector that can be used select IDs. The syntax for partial ID selector is -
var inputTextCatched = j$( 'input[id$=name]' ); //Find element with ID ending with name
The advantage here is that it will always find elements even if we change the page hierarchy as long as the id is ending with "name". Another important thing to check here is that I have prefaced the ID selector with input. The reason behind is that by prefacing input, jQuery will search for IDs ending with keyword "name" within HTML tag of type "input". So if you know the type of HTML tag, then it is always better to preface the ID selector with that tag to make the page more efficient.

So now the full code -
<apex:page id="page">
    <apex:form id="form">
        What is your name?
        <p/>
        <apex:inputText id="name" onfocus="myFunc();"/>
    </apex:form>
    <apex:includeScript value="{!URLFOR($Resource.jQuery1_11, '/js/jquery-1.11.2.min.js')}"/>
    <script>
        function myFunc() {
            var j$ = jQuery.noConflict();
            var inputTextCatched = j$( 'input[id$=name]' ); //Find element with ID ending with name
            inputTextCatched.val('Sudipta Deb');
        }
    </script>
</apex:page>    

Great. So with this approach we can keep all our JavaScript code in a single block, rather we can put all our JavaScript code in another file and upload the same as static resource in Salesforce. At the same time, we don't need to think about the page hierarchy.


Thanks and Good Night.

1 comment:

  1. "I very much enjoyed this article.Nice article thanks for given this information. i hope it useful to many pepole.php jobs in hyderabad.
    "

    ReplyDelete