February 18, 2010

Visualforce Page to Component JavaScript client side communication

On many occasions we might need to access some HTML DOM element inside a component from page using JavaScript. Example scenarios can be page fetching value of text field inside a component using JavaScript.

Though best is using native visualforce tags and server side communication as described here : http://wiki.developerforce.com/index.php/Controller_Component_Communication. As going client side requires careful usage of DOM element ids. So any minor change to html structure can easily break your code.

The Concept

In order to access anything on visualforce page you need to make sure element Id’s are assigned to each DOM element. That includes page, component, form, input fields etc

Once your DOM element ID’s are in place you can access any visualforce page element either using $Component global variable OR by manually forming correct id chains as per your element’s location in DOM. Using $Component is better practice, because when it is used inside a parent DOM element you don’t need to include parent’s ID to refer a child element.

To learn more about $Component variable go here. For those who want to do this manually, I would suggest using firebug add-on of Firefox, its great way to introspect in HTML DOM.

Code Sample

Communication will be illustrated using

  1. A Visualforce page named “PageCompCommunication.page”.
  2. A Component named “mycomp.component”.
  3. Apex controller class for component named “MyCompController”.

I will start with component and will finally illustrate the visualforce page.

“mycomp.component”

This is the component that’s meant to be nested inside a visualforce page. This component simply has an apex:form and a text field inside it. Please not in code sample below that every DOM element in component is having an ID.

<apex:component id="comp_id" controller="MyCompController">
	<h1>Component Text :</h1>
	<apex:form id="pageform_id">
		<apex:inputtext id="comptextinput" value="{!compInputText}" />
	</apex:form>
</apex:component>
“MyCompController”

This controller is just to bind the component’s text field. Its pretty simple apex code just having an attribute for the component’s input text field.

 
public class MyCompController {
  public String compInputText {get;set;}

  public MyCompController() {
    this.compInputText = 'Component Text Field Text';
  }
}
“PageCompCommunication.page”

This page encapsulates the component and has little javascript code to access the text field inside the component.  Following is the code for that page. Please note that using $Component saves us from prefixing the parent DOM element ID, so to access the same component text field is little simplified if we use this Global variable.

<apex:page id="page_id">

	<apex:sectionHeader title="Page to Component Test" />
	<!-- Clicking this will display the component's text field value -->
	<p><a href="#" onclick="javascript:showComponentInputValue()">Show
	Component Text Field Value </a></p>
	
	<script>
		function showComponentInputValue() {
			// on can use 
			// document.getElementById('page_id:mycomp_id:comp_id:pageform_id:comptextinput') 
			// but that will require you to prefix it with "page_id"
			// Using $Component inside parent doesn't 
			// reqires you to know the parent element id
			alert(document
               	 .getElementById('{!$Component.mycomp_id:comp_id:pageform_id:comptextinput}').value);
	
		}
	</script>


	<hr />
	<!-- COMPONENT CODE STARTS HERE -->
	<c:mycomp id="mycomp_id" />
	<!-- COMPONENT CODE STARTS ENDS -->
	<hr />

</apex:page>

Here is the screenshot that shows the alert getting displayed with component’s text field value, when the hyperlink is clicked.