Visualforce – jQuery pattern – enforce only single checkbox in a list

Over the last few months, I’ve dabbled in adding some client-side improvements to Visualforce pages. But, I’ve resisted doing much with Javascript and jQuery in order to keep the development models limited to just Visualforce, Apex, and Force.com. There was something about a blend of Javascript and VF markup on a page that I always found jarring and hard to read and understand – too much syntactic dissonance

But, jQuery and jQuery Mobile are highly recommended for developing Salesforce1 apps. After reading jQuery Mobile Web Development Essentials, Second Edition by Camden and Matthews, I discovered a nice organizing pattern for jQuery that was a good place to add in all of a page’s jQuery event handlers (see chapter 8). So, I decided to apply it to a commonly-occurring problem – display a list with checkboxes next to each row, but allow only one box to be checked before submission to the server. This avoids writing controller code to enforce a single selection (as radiobuttons can’t easily be applied to table rows).

So, here it is where the table displays a list of Quotes on an Opportunity and only one can be specified for the action

<apex:page standardController="Opportunity" extensions="OppoControllerExtension">

	<apex:includescript value="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js" />
	<script>
		$j = jQuery.noConflict();		//	reassign $ to $j to avoid conflict with VF
		$j(function() {				// 	jQuery shorthand for $(document).ready(function() ..  Wait until page loads 
			//	define the application
			var	OppoToSvcContract	= {};
			
			(function(app) {		//	Define anon function
				//	--------------------------
				//	variable definitions
				//	--------------------------
		
				//	--------------------------
				//	init:	do initializations
				//	--------------------------
				app.init	= function() {
					app.bindings();		//	establish bindings	
				};
		
				//	-----------------------------------
				//	bindings:  events to event handlers
				//	-----------------------------------
				app.bindings = function() {
					// set up binding for onclick checkbox: Unchecks other checkboxes
					$j('input[id*="qCheckbox"]').click(function(e) {		// attach anonymous fn as event handler to click event for all DOM checkbox whose id attr contains qCheckbox, $j(this) available
						var clickedElmId	= $j(this).attr('id');			// DOM elm that was clicked
						$j('input[id*="qCheckbox"]').each(function() {		// Go thru all checkboxes
							if ($j(this).attr('id') != clickedElmId) {		// if id diff than clicked elm id, uncheck	
								$j(this).removeProp('checked');
							}
						});
					});													// end binding
				};														// end all bindings
				
				app.init();				// Anon function invokes its own init function
			}) (OppoToSvcContract);		// Execute anon function passing in an object representing our application
				
				
		});	
	</script>





	<apex:sectionHeader title="Create a Service Contract from this Opportunity's Quotes:" subTitle="{!Opportunity.name}"/>
	
	<apex:form id="theForm">
		<apex:pageMessages/> 
		<apex:pageBlock >
			<apex:pageBlockButtons location="top">
		 		<apex:commandbutton value="Create Service Contract from Oppo+Quote" 
						action="{!createSvcContract}"/>
		 		<apex:commandbutton value="Cancel" immediate="true" action="{!cancel}"/>      
			</apex:pageBlockButtons>
			
			
		</apex:pageBlock>
		
		<apex:pageBlock title="Quotes (to use as source for Service Contract line items)">
	
			<apex:pageBlockTable id="quotesTbl" value="{!availQuotes}" var="aq" style="width:90%; border-color: rgb(248,248,248);" headerClass="quoteTblHdr">
                <apex:column headerValue="Select One" style="width: 5%;">
                	<apex:inputCheckbox id="qCheckbox" value="{!aq.isSelected}"/>  <!--  jQuery event handler takes care of only one box checkable -->
                </apex:column>   
                <apex:column headerValue="Name" style="width: 10%">
					<apex:outputLink value="{!URLFOR($Action.Quote__c.View,aq.qw.q.id)}">{!aq.qw.q.name} {!aq.forecastMsg}</apex:outputLink> 
				</apex:column>    
			</apex:pageBlockTable>
         </apex:pageBlock>		
	</apex:form>
</apex:page>

Leave a Reply

Your email address will not be published. Required fields are marked *