<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Force2b Technology Consultant</title>
	<atom:link href="http://www.force2b.net/index.php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.force2b.net</link>
	<description></description>
	<lastBuildDate>Tue, 17 Aug 2010 13:11:21 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0.1</generator>
		<item>
		<title>Icons available SalesForce.com</title>
		<link>http://www.force2b.net/index.php/2010/08/salesforce-icons/</link>
		<comments>http://www.force2b.net/index.php/2010/08/salesforce-icons/#comments</comments>
		<pubDate>Mon, 16 Aug 2010 14:20:22 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[SalesForce.com]]></category>

		<guid isPermaLink="false">http://www.force2b.net/?p=364</guid>
		<description><![CDATA[SalesForce.com Icons Available for VisualForce Pages and Formulas]]></description>
			<content:encoded><![CDATA[<p><a href="http://free-121d5f44d20-121d603d1c5-121ee2b8103.force.com/force2b/salesforceicons"><img class="alignright size-medium wp-image-366" title="SalesForceIcons" src="http://www.force2b.net/wp-content/uploads/2010/08/SalesForceIcons-300x201.png" alt="" width="300" height="201" /></a>Like many of you, when building a VisualForce page, or sometimes an Image Formula, I find myself looking for icons to use on the page. Of course, whenever possible I want like the icons to look like they belong in  SalesForce.com.</p>
<p>As you might expect, SalesForce.com has a series of icons available for public use, though with the exception of the &#8220;Samples&#8221; icons at the bottom of the page linked below, none of these icons are &#8220;official&#8221; and so there is always that possibility that they may disappear or change without notice.</p>
<p>The link below is to a Sites page that displays the icons I found by reviewing the CSS and browsing through the Discussion boards. Technically, there are many other images you can find by examining the CSS or SalesForce source, however many of these were Sprites or background images that we&#8217;re necessarily re-usable &#8220;icons&#8221;.</p>
<p>To get the URL for a given icon, right-click on it and select &#8220;View Image&#8221; or &#8220;Copy Image Location&#8221;. When copying the URL for the image, do <strong>not</strong> link to these specifc images using my free Sites URL. Instead, your VisualForce page should reference the relative path to the image as it&#8217;s stored on SalesForce.com&#8217;s site:</p>
<p style="padding-left: 30px;">Example: &lt;img src=&#8221;/img/arrow_dwn.gif&#8221; /&gt; OR &lt;apex:image value=&#8221;/img/arrow_dwn.gif&#8221; /&gt; to render as  <img src="http://free-121d5f44d20-121d603d1c5-121ee2b8103.force.com/img/arrow_dwn.gif" alt="" /></p>
<p><a href="http://free-121d5f44d20-121d603d1c5-121ee2b8103.force.com/force2b/salesforceicons" target="_blank">http://free-121d5f44d20-121d603d1c5-121ee2b8103.force.com/force2b/salesforceicons</a></p>
<p><strong><strong><strong>Note:  Please add a comment to this post if you have found other icons that should be included in this list. </strong></strong></strong></p>
<p><strong><strong> </strong></strong></p>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2010/08/salesforce-icons/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Date Time and Timezone Handling in Apex</title>
		<link>http://www.force2b.net/index.php/2010/08/date-time-and-timezone-handling-in-apex/</link>
		<comments>http://www.force2b.net/index.php/2010/08/date-time-and-timezone-handling-in-apex/#comments</comments>
		<pubDate>Tue, 10 Aug 2010 16:50:56 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[Blog]]></category>
		<category><![CDATA[SalesForce.com]]></category>

		<guid isPermaLink="false">http://www.force2b.net/?p=356</guid>
		<description><![CDATA[Date Time and Time zone Conversions for Apex code]]></description>
			<content:encoded><![CDATA[<p>I recently had to do some work converting timezones in Apex. Unfortunately, Apex is missing some key conversion functionality when it comes to handling times. I created this class to handle figuring out the time-offset of the current user (hardcoded to Eastern Time) and then use that to convert a time in another timezone. It also has a couple of handy methods for retrieving DST start/end dates and getting a list of US timezones with GMT offset.</p>
<p>Hopefully someone else out there will find this useful if they need to handle datetime conversions in their Apex code.</p>
<pre>
/* **********************************************************************************************
* TimeConversions Class
* Created by: Michael Smith/Force2b, 04/06/2010
*
************************************************************************************************ */
global class TimeConversions {
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;/* -------------------------------------------------------------------------------------
&nbsp;&nbsp;&nbsp;* Returns an Integer  of the Timezone Offset from Eastern Time for the
&nbsp;&nbsp;&nbsp;* currently logged in user
&nbsp;&nbsp;&nbsp;*
&nbsp;&nbsp;&nbsp;* This is used to convert the String DateTime (that is in Eastern Time) into a
&nbsp;&nbsp;&nbsp;* DateTime value in SalesForce. The default behavior of SFC converts the string into
&nbsp;&nbsp;&nbsp;* a local datetime value, but we need to get into Eastern Time.
&nbsp;&nbsp;&nbsp;* ------------------------------------------------------------------------------------- */
&nbsp;&nbsp;&nbsp;public Integer getCurrentUserTZOffsetFromEastern() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&lt;String, Integer[]&gt; tzSIDKeys = getTZSidKeys();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;User user = [SELECT ID, TimeZoneSidKey FROM User WHERE ID = :UserInfo.getUserId() LIMIT 1];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Date[] dstDatesNow = getDSTDates(System.Today().year());
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Integer UsersTZOffset = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (tzSIDKeys.get(user.TimeZoneSidKey) != null) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Get the base timezone offset from GMT for the user
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (System.Today() &gt;= dstDatesNow[0] &#038;&#038; System.Today() &lt;= dstDatesNow[1]) UsersTZOffset = tzSIDKeys.get(user.TimeZoneSidKey)[1];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else UsersTZOffset = tzSIDKeys.get(user.TimeZoneSidKey)[0];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;system.debug(LoggingLevel.Error, 'Base TimeZone for Current User=' + user.TimeZoneSidKey + '/' + UsersTZOffset );
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// Now make it a timezone offset from EASTERN time
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Integer EasternTZOffset = 0;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (System.Today() &gt;= dstDatesNow[0] &#038;&#038; System.Today() &lt;= dstDatesNow[1]) EasternTZOffset = tzSIDKeys.get('America/New_York')[1];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else EasternTZOffset = tzSIDKeys.get('America/New_York')[0];
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UsersTZOffset = Math.abs(EasternTZOffset) - Math.abs(UsersTZOffset);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;system.debug(LoggingLevel.Error, 'TimeZone Offset to Eastern Time=' + UsersTZOffset );
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return UsersTZOffset ;
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;/* -------------------------------------------------------------------------------------
&nbsp;&nbsp;&nbsp;* Returns a String Collection of the Timezone Codes based on the Timezone Offset Passed
&nbsp;&nbsp;&nbsp;* for the date passed.
&nbsp;&nbsp;&nbsp;*
&nbsp;&nbsp;&nbsp;* Based on a table from: http://en.wikipedia.org/wiki/Zone.tab
&nbsp;&nbsp;&nbsp;*
&nbsp;&nbsp;&nbsp;* getTimeZoneCode[0] = Display Text (ex: EDT)
&nbsp;&nbsp;&nbsp;* getTimeZoneCode[1] = DateTime.Format() parameter (ex: America/New_York)
&nbsp;&nbsp;&nbsp;* ------------------------------------------------------------------------------------- */
&nbsp;&nbsp;&nbsp;public string[] getTimeZoneCode(Integer tzOffset, Date theDate, Boolean isDSTObserved) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Date[] dstDates = getDSTDates(theDate.year()); // [0]=startDate, [1]=endDate
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;boolean isDSTOn = (theDate &gt;= dstDates[0] &#038;&#038; theDate &lt;= dstDates[1]);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;if (tzOffset == 0) return new String[]{' GMT', 'Europe/London' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 4) return new String[]{' AST (UTC-04)', 'America/Puerto_Rico' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 5 &#038;&#038; isDSTOn &#038;&#038; isDSTObserved) return new String[]{' EDT (UTC-04)', 'America/New_York' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 5) return new String[]{' EST (UTC-05)', 'America/New_York' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 6 &#038;&#038; isDSTOn &#038;&#038; isDSTObserved) return new String[]{' CDT (UTC-05)', 'America/Chicago' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 6) return new String[]{' CST (UTC-06)', 'America/Chicago' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 7 &#038;&#038; !isDSTObserved)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   return new String[]{' MST (UTC-07)', 'America/Phoenix' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 7 &#038;&#038; isDSTOn &#038;&#038; isDSTObserved) return new String[]{' MDT (UTC-06)', 'America/Denver' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 7) return new String[]{' MST (UTC-07)', 'America/Denver' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 8 &#038;&#038; isDSTOn &#038;&#038; isDSTObserved) return new String[]{' PDT (UTC-07)', 'America/Los_Angeles' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 8) return new String[]{' PST (UTC-08)', 'America/Los_Angeles' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 9 &#038;&#038; isDSTOn &#038;&#038; isDSTObserved) return new String[]{' AKDT (UTC-08)', 'America/Anchorage' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 9) return new String[]{' AKST (UTC-09)', 'America/Anchorage' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 10 &#038;&#038; !isDSTObserved)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;  return new String[]{' HST (UTC-10)', 'Pacific/Honolulu' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 10 &#038;&#038; isDSTOn &#038;&#038; isDSTObserved) return new String[]{' HDT (UTC-09)', 'America/Adak' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 10) return new String[]{' HST (UTC-10)', 'America/Adak' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else if (tzOffset == 11) return new String[]{' HST (UTC-10)', 'Pacific/Pago_Pago' };
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;else return new String[]{' UTC-' + tzOffset, 'GMT' };
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;/* -------------------------------------------------------------------------------------
&nbsp;&nbsp;&nbsp;* Returns a date Collection of Start/End dates for US Daylight Saving Time
&nbsp;&nbsp;&nbsp;* for the specified year.
&nbsp;&nbsp;&nbsp;*
&nbsp;&nbsp;&nbsp;* Based on code from: http://www.webexhibits.org/daylightsaving/b2.html
&nbsp;&nbsp;&nbsp;* ------------------------------------------------------------------------------------- */
&nbsp;&nbsp;&nbsp;public Date[] getDSTDates(Integer theYear) {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long thisYear;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long AprilDate;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long OctoberDate;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long MarchDate;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long NovemberDate;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Long longSeven = 7;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thisYear = Math.round(theYear);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;AprilDate = Math.mod(2+6 * thisYear - Math.floor(thisYear / 4).longValue(), longSeven) + 1;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;OctoberDate=  Math.mod(31-( Math.floor(thisYear * 5 / 4).longValue() + 1), longSeven);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;MarchDate = 14 - Math.mod(Math.floor(1 + thisYear * 5 / 4).LongValue(), longSeven);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;NovemberDate = 7 - Math.mod(Math.floor (1 + thisYear * 5 / 4).LongValue(), longSeven);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string startDate = (thisYear &gt; 2006 ? ('03/'+MarchDate) : ('04/'+AprilDate)) + '/' + thisYear;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;string endDate = (thisYear &gt; 2006 ? ('11/'+NovemberDate):('10/'+OctoberDate))+ '/' + thisYear;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Date[] rtnDates = new List&lt;Date&gt;();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rtnDates.add(Date.parse(startDate));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rtnDates.add(Date.parse(endDate));
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return rtnDates;
&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;public Map&lt;String, Integer[]&gt; getTZSidKeys() {
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Map&lt;String, Integer[]&gt; tzSIDKeys = new Map&lt;String, Integer[]&gt;();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Adak', new Integer[]{-10, -9});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Anchorage', new Integer[]{-9, -8});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Chicago', new Integer[]{-6, -5});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Denver', new Integer[]{-7, -6});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Detroit', new Integer[]{-5, -4});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Halifax', new Integer[]{-4, -3});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Indianapolis', new Integer[]{-5, -4});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Los_Angeles', new Integer[]{-8, -7});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Montreal', new Integer[]{-5, -4});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/New_York', new Integer[]{-5, -4});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Panama', new Integer[]{-5, -5});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Phoenix', new Integer[]{-7, -7});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Puerto_Rico', new Integer[]{-4, -4});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Toronto', new Integer[]{-5, -4});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('America/Vancouver', new Integer[]{-8, -7});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('Europe/London', new Integer[]{0, 1});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('Pacific/Honolulu', new Integer[]{-10, -10});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tzSIDKeys.put('Pacific/Pago_Pago', new Integer[]{-11, -11});
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return tzSIDKeys;
&nbsp;&nbsp;&nbsp;}
}
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2010/08/date-time-and-timezone-handling-in-apex/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Getting ActionSupport to Rerender Elements on a Page</title>
		<link>http://www.force2b.net/index.php/2010/06/getting-actionsupport-to-rerender-elements-on-a-page/</link>
		<comments>http://www.force2b.net/index.php/2010/06/getting-actionsupport-to-rerender-elements-on-a-page/#comments</comments>
		<pubDate>Wed, 23 Jun 2010 10:57:40 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[SalesForce.com]]></category>
		<category><![CDATA[VisualForce]]></category>

		<guid isPermaLink="false">http://www.sfcnmore.com/?p=305</guid>
		<description><![CDATA[How to get the VisualForce apex:ActionSupport tag to rerender elements based on field value changes]]></description>
			<content:encoded><![CDATA[<p>Up until today I have been struggling with getting the <a href="http://www.salesforce.com/us/developer/docs/pages/Content/pages_compref_actionSupport.htm" target="_blank">apex:actionSupport</a> tag to work as documented. Apparently, it looks like VisualForce is extremely picky about what it will  rerender. I found this great post on the developer boards that resolved my  issue.</p>
<p><a href="http://community.salesforce.com/t5/Visualforce-Development/actionSupport-rerender-problem/m-p/150628/highlight/true#M17485">http://community.salesforce.com/t5/Visualforce-Development/actionSupport-rerender-problem/m-p/150628/highlight/true#M17485</a></p>
<p>What it came down to was making sure that the elements being  rerendered did not have a rendered=&#8221;" attribute in the  tag. For example,  in the code below I wanted to hide the second picklist if the value of the first  picklist was &#8216;Standard&#8217;. I kept trying to rerender the pageBlockSectionItem area  and it wouldn&#8217;t work. By wrapping the pageBlockSectionItem block inside of  another tag (pageBlockSection in this case) and then rerendering <em>that</em> ID in the actionSupport tag. I tried wrapping it in an outputPanel tag, but that  screws up the formatting of the labels and fields. The same was true for  the <em><span style="color: #800000;">customConfigurationPanel</span></em> area. I wrapped  that pageBlock in an outputPanel tag and made sure the rendered attribute was on  the pageBlock not the outputPanel tag. Works great.</p>
<pre>
&lt;apex:pageBlock id="MainConfigurationBlock" title="Standard Integration Options"
&lt;apex:pageBlockSection id="configTypeSection" columns="1"&gt;
   &lt;apex:pageBlockSectionItem &gt;
      &lt;apex:outputLabel&gt;Integration Type&lt;/apex:outputLabel&gt;
      &lt;apex:selectList value="{!config.IntegrationType__c}" size="1"&gt;
         &lt;apex:selectOption itemValue="Standard" itemLabel="Standard"/&gt;
         &lt;apex:selectOption itemValue="Custom" itemLabel="Custom"/&gt;
         &lt;apex:actionSupport event="onchange" status="StatusChange"
          rerender="activityObjectSection,customConfigurationPanel" /&gt;
      &lt;/apex:selectList&gt;
   &lt;/apex:pageBlockSectionItem&gt;
&lt;/apex:pageBlockSection&gt;

&lt;apex:pageBlockSection id="activityObjectSection" columns="1"&gt;
   &lt;apex:pageBlockSectionItem rendered="{!config.IntegrationType__c = 'Custom'}"&gt;
      &lt;apex:outputLabel id="activityObjectLabel"&gt;Activity Object&lt;/apex:outputLabel&gt;
      &lt;apex:selectList id="activityObjectField" value="{!config.ActivityObject__c}" size="1"
      rendered="{!config.IntegrationType__c = 'Custom'}" &gt;
         &lt;apex:selectOptions value="{!objects}"/&gt;
      &lt;/apex:selectList&gt;
   &lt;/apex:pageBlockSectionItem&gt;
&lt;/apex:pageBlockSection&gt;
&lt;/apex:pageBlock&gt;

&lt;apex:actionStatus startText="Updating page ..." id="StatusChange"/&gt;

&lt;apex:outputPanel id="customConfigurationPanel"&gt;
   &lt;apex:pageBlock id="customConfigurationBlock" title="Custom Integration Options"
   rendered="{!config.IntegrationType__c='Custom' &#038;&#038; config.ActivityObject__c != null}"&gt;

    ..... other fields that I don't want displayed  ....
    ..... if the IntegrationType is "Standard"      ....

   &lt;/apex:pageBlock&gt;
&lt;/apex:outputPanel id="customConfigurationPanel"&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2010/06/getting-actionsupport-to-rerender-elements-on-a-page/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hiding Edit Links for Related Lists/Views on a VisualForce Page</title>
		<link>http://www.force2b.net/index.php/2010/06/hiding-edit-links-for-related-listsviews-on-a-visualforce-page/</link>
		<comments>http://www.force2b.net/index.php/2010/06/hiding-edit-links-for-related-listsviews-on-a-visualforce-page/#comments</comments>
		<pubDate>Wed, 16 Jun 2010 14:58:02 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[SalesForce.com]]></category>
		<category><![CDATA[jQuery]]></category>
		<category><![CDATA[VisualForce]]></category>

		<guid isPermaLink="false">http://www.sfcnmore.com/?p=299</guid>
		<description><![CDATA[I had a situation the other day where I needed to hide the Edit &#38; Del links that appear on both the ListView and Related Lists. Luckily in both cases the pages were VisualForce pages, but I did not want to manually recreate the ListViews or Related Lists by hand. My solution was to use jQuery to quickly select and]]></description>
			<content:encoded><![CDATA[<p>I had a situation the other day where I needed to hide the Edit &amp; Del links that appear on both the ListView and Related Lists. Luckily in both cases the pages were VisualForce pages, but I did not want to manually recreate the ListViews or Related Lists by hand.</p>
<p>My solution was to use jQuery to quickly select and hide all elements that had a class of &#8220;actionLink&#8221;:</p>
<pre>&lt;apex:page tabStyle="Workshops__tab"&gt;

&lt;apex:includeScript value="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"/&gt;

&lt;apex:sectionHeader title="Data Entry Portal" subTitle="Workshops" /&gt;
&lt;apex:pageMessages /&gt;

	&lt;apex:ListViews type="Workshop__c" /&gt;

&lt;script&gt;
    // Using jQuery, hide all of the actionLinks (edit link specifically) on the Workshops
    // This forces the user to click the Workshop name and then click the [Edit] button
    $(".actionLink").css("display","none");
&lt;/script&gt;

&lt;/apex:page&gt;</pre>
<p>I also posted an Idea to the Idea Exchange to allow easy selection of which links should appear on the standard List Views and Related Lists: <a href="https://sites.secure.force.com/ideaexchange/ideaView?c=09a30000000D9xt&amp;id=08730000000I3uN" target="_blank">https://sites.secure.force.com/ideaexchange/ideaView?c=09a30000000D9xt&amp;id=08730000000I3uN</a></p>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2010/06/hiding-edit-links-for-related-listsviews-on-a-visualforce-page/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Aggregate SOQL Functions</title>
		<link>http://www.force2b.net/index.php/2010/02/aggregate-soql-functions/</link>
		<comments>http://www.force2b.net/index.php/2010/02/aggregate-soql-functions/#comments</comments>
		<pubDate>Wed, 03 Feb 2010 17:54:07 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[SalesForce.com]]></category>
		<category><![CDATA[Apex Code]]></category>
		<category><![CDATA[Apex Trigger]]></category>

		<guid isPermaLink="false">http://www.sfcnmore.com/?p=294</guid>
		<description><![CDATA[Aggregate functions in SalesForce.com SOQL]]></description>
			<content:encoded><![CDATA[<p>I couldn’t be happier that the new 18.0 (Spring ’10) API Release from SalesForce.com now supports aggregate functions in SOQL.</p>
<p>Links to resources:</p>
<ul>
<li><a href="http://developer.force.com/releases/release/Spring10/Aggregate+Functions">http://developer.force.com/releases/release/Spring10/Aggregate+Functions</a></li>
<li><a href="http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_soql_select.htm">http://www.salesforce.com/us/developer/docs/api/Content/sforce_api_calls_soql_select.htm</a></li>
</ul>
<p>The new SUM() and GROUP BY features can really simplify writing custom Roll-up Triggers.</p>
<p>Below is a relatively simple Trigger that rolls up Budget numbers by the Previous, Current and Next year to the parent Program__c object. By using the Calendar_Year() function, you can see how easy it is to create a single SOQL statement that does the summing in a single statement.</p>
<pre>trigger Program_Budget_Rollup on Program_Budget__c (after delete, after insert, after update) {

    Set&lt;String&gt; programIDs = new Set&lt;String&gt;();

    //************************************************
    // Build a LIST of Program ID's that will
    // need recalculating
    //************************************************
    if(Trigger.isInsert || Trigger.isUpdate){
        for(Program_Budget__c te : trigger.new){
            if(te.Program__c != null){
                if(!programIDs.contains(te.Program__c)) programIDs.add(te.Program__c);
            }
        }
    }  // INSERT/UPDATE Trigger

    if(Trigger.isDelete || Trigger.isUpdate){
        for(Program_Budget__c te : trigger.old){
            if(te.Program__c != null){
                if(!programIDs.contains(te.Program__c)) programIDs.add(te.Program__c);
            }
        }
    }  // DELETE/UPDATE Trigger

    if(programIDs .size() &gt; 0) {

        Map&lt;ID, Program__c&gt; programs = new Map&lt;ID, Program__c&gt;();
        Program__c d = null;

        for (AggregateResult dr : [SELECT Program__c, CALENDAR_YEAR(Date_c) Year, SUM(Amount__c) Amount
        FROM Program_Budget__c GROUP BY Program__c, CALENDAR_YEAR(Date__c)]) {

            String dID = (string)dr.Get('Program__c');
            // get the record or create a new one
            if (programs.get(dID) == null)
                d = new Program__c(ID = dID,
                Previous_Year_Budget__c = 0,
                Current_Year_Budget__c = 0,
                Next_Year_Budget__c = 0,
                Total_Budget__c = 0);
            else
               d = programs.get(dID);

            // update the donation total fields
            Decimal amt = (Decimal)dr.Get('Amount');
            String fyr = (String)dr.GetDate('Year');
            Integer yr = Integer.valueOf(fyr);
            if (yr == Date.today().year()) d.Current_Year_Budget__c = amt;
            if (yr == (Date.today().year() - 1)) d.Previous_Year_Budget__c = amt;
            if (yr == (Date.today().year() + 1)) d.Next_Year_Budget__c = amt;
            d.Total_Budget__c = d.Total_Budget__c + amt;

            // push the record back into the Map
            programs.put(dID, d);
        }

        //commit the changes to Salesforce
        update programs.values();

    }

}</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2010/02/aggregate-soql-functions/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Hiding Custom Buttons on a VisualForce Page</title>
		<link>http://www.force2b.net/index.php/2009/10/hiding-custom-buttons-on-a-visualforce-page/</link>
		<comments>http://www.force2b.net/index.php/2009/10/hiding-custom-buttons-on-a-visualforce-page/#comments</comments>
		<pubDate>Fri, 16 Oct 2009 23:33:15 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[SalesForce.com]]></category>
		<category><![CDATA[VisualForce]]></category>

		<guid isPermaLink="false">http://www.sfcnmore.com/?p=261</guid>
		<description><![CDATA[Sorry it’s been so long time since my last blog post. Life and work just seem to get in the way. I recently wanted to setup some custom buttons that could be dynamically hidden or renamed on the page. As you probably know, SalesForce.com does not currently have the ability to hide buttons on a page layout. However, it can]]></description>
			<content:encoded><![CDATA[<p>Sorry it’s been so long time since my last blog post. Life and  work just seem to get in the way.</p>
<p>I recently wanted to setup some custom buttons that could be dynamically hidden or renamed on the page. As you probably know, SalesForce.com does not currently have the ability to hide buttons on a page layout. However, it can be done through a combination of VisualForce and JavaScript.</p>
<p>Idea to vote on: <a title="http://ideas.salesforce.com/article/show/101209/Limit_the_Visibility_of_a_Custom_Button" href="http://ideas.salesforce.com/article/show/101209/Limit_the_Visibility_of_a_Custom_Button" target="_blank">http://ideas.salesforce.com/article/show/101209/Limit_the_Visibility_of_a_Custom_Button</a></p>
<p>The most important thing to note here is that this can only be done on a VisualForce page. It’s not possible to hide or take any actions on custom buttons that are on a standard page. This is due to cross-site scripting limitations of all browsers that prevent JavaScript from modifying the DOM of a window at another domain. You’ll see why as we get into the coding.</p>
<p>To start, I’ve taken a simple custom object and created an even simpler VisualForce page  to use for the VIEW. Once created, just override the VIEW option with this page.</p>
<pre>&lt;apex:page standardController="Application__c" title="Application For {!Application__c.Contact_Name__c}" &gt;
    &lt;apex:Detail subject="{!Application__c.ID}" relatedList="true" /&gt;
&lt;/apex:page&gt;</pre>
<p>At first, the result is visually the same. Now let’s add a custom button to the page.</p>
<p><img class="aligncenter size-full wp-image-262" title="Screenshot_NewButton" src="http://www.sfcnmore.com/wp-content/uploads/2009/10/Screenshot_NewButton.jpg" alt="Screenshot_NewButton" width="535" height="380" /></p>
<p>In this case, I named the button &#8220;Update_Status&#8221;. The &#8216;Name&#8217; is critical to modifying the button in the VisualForce. Though, the name must always be lowercase in your VisualForce page. For example, even though I have &#8220;Update_Status&#8221; as the Name here, my VisualForce code will reference &#8220;update_status&#8221;.</p>
<p>Now comes the fun. By adding some JavaScript to the VisualForce page you can manipulate the button – hide it, disable it, or even change the button label.</p>
<pre>&lt;script&gt;
function hideButton(btnName) {
  try{
    var buttons = parent.document.getElementsByName(btnName);
    for (var i=0; i &lt; buttons.length; i++) {
      buttons[i].className="btnDisabled ";
      buttons[i].disabled=true;
      buttons[i].type='hidden';
    }
  } catch(e) {
    // var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
  }
}

function renameButton(btnName, newTitle) {
  try{
    var buttons = parent.document.getElementsByName(btnName);
    for (var i=0; i &lt; buttons.length; i++) {
      buttons[i].value=newTitle;
    }
  } catch(e) {
    // var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
  }
}
&lt;/script&gt;</pre>
<p>We’ll start with the above two functions. By passing in a button name to the hideButton() function we can hide it on the page. Passing in the same button name and a new title to renameButton() will change the button label on the page. Below is my full VisualForce page code:</p>
<pre>&lt;apex:page standardController="Application__c" title="Application For {!Application__c.Contact_Name__c}" &gt;
    &lt;apex:Detail subject="{!Application__c.ID}" relatedList="true" /&gt;

&lt;script type="text/javascript"&gt;
// The code below is executed as soon as the page loads. Based on the value of the Status__c field
// it either hides or renames the update_status button
if ('{!Application__c.Status__c}' == 'Submitted') renameButton("update_status", "Mark as In-Review");
if ('{!Application__c.Status__c}' == 'In-Review') hideButton("update_status");
if ('{!Application__c.Status__c}' == 'Deposit Pending') renameButton("update_status", "Confirm Deposit Received");
if ('{!Application__c.Status__c}' == 'Deposit Received') hideButton("update_status");
if ('{!Application__c.Status__c}' == 'Approved') hideButton("update_status");
if ('{!Application__c.Status__c}' == 'Rejected') hideButton("update_status");

function hideButton(btnName) {
  try{
    var buttons = parent.document.getElementsByName(btnName);
    for (var i=0; i &lt; buttons.length; i++) {
      buttons[i].className="btnDisabled ";
      buttons[i].disabled=true;
      buttons[i].type='hidden';
    }
  } catch(e) {
    // var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
  }
}

function renameButton(btnName, newTitle) {
  try{
    var buttons = parent.document.getElementsByName(btnName);
    for (var i=0; i &lt; buttons.length; i++) {
      buttons[i].value=newTitle;
    }
  } catch(e) {
    // var ee = e.message || 0; alert('Error: \n\n'+e+'\n'+ee);
  }
}
&lt;/script&gt;</pre>
<p>Screen captures of the page with button showing and hidden:</p>
<p><img class="aligncenter size-full wp-image-286" title="ScreenCapture_WithButton" src="http://www.sfcnmore.com/wp-content/uploads/2009/10/ScreenCapture_WithButton.jpg" alt="ScreenCapture_WithButton" width="523" height="103" /><img class="aligncenter size-full wp-image-287" title="ScreenCapture_WithoutButton" src="http://www.sfcnmore.com/wp-content/uploads/2009/10/ScreenCapture_WithoutButton.jpg" alt="ScreenCapture_WithoutButton" width="523" height="103" /></p>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2009/10/hiding-custom-buttons-on-a-visualforce-page/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>Change a Tab to Open to a Default View</title>
		<link>http://www.force2b.net/index.php/2009/06/open-tab-to-default-view/</link>
		<comments>http://www.force2b.net/index.php/2009/06/open-tab-to-default-view/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 19:58:12 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[SalesForce.com]]></category>
		<category><![CDATA[Tab]]></category>
		<category><![CDATA[VisualForce]]></category>

		<guid isPermaLink="false">http://www.sfcnmore.com/?p=251</guid>
		<description><![CDATA[By default, when you click on any standard SalesForce.com Tab for an Object, it brings you to a list of “Recently Viewed” items. I, like many others, find this annoying. I’d much rather that SalesForce.com give us options to change the default View by Tab, ideally for each user Profile. In the mean time, the work-around was to use an]]></description>
			<content:encoded><![CDATA[<p><img class="alignright size-medium wp-image-255" title="view-recent-items" src="http://www.sfcnmore.com/wp-content/uploads/2009/06/view-recent-items-300x145.jpg" alt="view-recent-items" width="300" height="145" />By default, when you click on any standard SalesForce.com Tab for an Object, it brings you to a list of “Recently Viewed” items. I, like many others, find this annoying. I’d much rather that SalesForce.com give us options to change the default View by Tab, ideally for each user Profile.</p>
<p>In the mean time, the work-around was to use an S-Control to redirect the user to the custom view. However, with the upcoming deprecation of S-Controls in 2010, we should be writing these as VisualForce pages instead.</p>
<h3>S-Control Version:</h3>
<pre>&lt;html&gt;
&lt;head&gt;
&lt;script language="Javascript"&gt;
function init()
{
     parent.document.location.href= "/003?fcf=00B30000005a5FO";
}
&lt;/script&gt;
&lt;/head&gt;
&lt;body onload="init()"&gt;
&lt;center&gt;&lt;h2&gt;Please Wait ..... Loading Contacts Tab&lt;/h2&gt;&lt;/center&gt;
&lt;/body&gt;
&lt;/html&gt;</pre>
<h3>VisualForce Version</h3>
<p>So, I decided to take a stab at converting a more sophisticated version of the above S-Control into a VisualForce page. The key, though, was to completely avoid using Apex so that the page can be modified in Production without having to go through the Sandbox/Test/Deploy steps required with Apex. This is accomplished by using JavaScript for the page logic, basically the same as the S-Control. It just has to be wrapped within the Apex:Page tags and the startup JavaScript logic is slightly different.</p>
<p>The resulting VisualForce page shown below does the following:</p>
<ul>
<li>Display a loading message.</li>
<li>Retrieves the Prefix for the Contact object (‘003’ typically). You can substitute Contact for any object that you want this page to work with.</li>
<li>Uses a simple Switch/Case statement based on the Users Role Name to determine which View to load. This is where it’s necessary hardcode the View ID’s. Of course, since we have no Apex it’s easy to modify these at any time on the fly.</li>
<li>Redirect the user to that view URL</li>
</ul>
<pre>&lt;apex:Page tabStyle="Contact" &gt;
&lt;script src="/soap/ajax/15.0/connection.js"&gt;&lt;/script&gt;
&lt;script type="text/javascript" /&gt;
&lt;script&gt;
     window.onload = function() {

     sforce.connection.sessionId = '{!$Api.Session_ID}';

     var describeSObjectResult = sforce.connection.describeSObject("contact");
     var prefix = describeSObjectResult.keyPrefix;

     // Determine the View based on the Role of the User
     var cView;
     switch ( "{!$UserRole.Name}" ) {
     case "North America": cView = "00B30000001Ysw2" ; break ;
     case "EMEA": cView = "00B30000001Ysw4" ; break ;
     case "Europe": cView = "00B30000001Ysw5" ; break ;
     case "SEA": cView = "00B30000001Ysw6" ; break ;
     case "South East Asia": cView = "00B30000001Ysw7" ; break ;
     case "Australia": cView = "00B30000001Ysw8" ; break ;
     default: cView = "00B30000001Ysw3"; break;
     }

     // Change the whole window to point to this location
     parent.document.location.href = "/" + prefix + "?fcf=" + cView ;
}
&lt;/script&gt;
&lt;center&gt;&lt;h2&gt;Please Wait ..... Loading 'Your' Tab&lt;/h2&gt;&lt;/center&gt;
&lt;/apex:page&gt;</pre>
<p>To implement this in your Org:</p>
<ul>
<li>Copy the ID’s for each of the View’s you want reference in your page. If you want everyone to default to the same view, then you only need the one ID.</li>
<li>Create a new VisualForce Page and paste in the code above.</li>
<li>Replace “Contact” on the the <strong>tabStyle </strong>and <strong>describeSObject </strong>lines to the object you are creating a tab for</li>
<li>Modify the Role Names or use {!$Profile.Name} if you prefer to set the default view by Profile.</li>
<li>Modify the view ID’s in the Switch/Case lines as appropriate.</li>
<li>If you want everyone to go to the same view, delete the Switch/Case block and add <strong>= “<em>view Id</em>”</strong> to the <strong>var cView;</strong> line.</li>
<li>Save your Page.</li>
<li>Override the Tab to point to this new VisualForce page<br />
<img class="alignnone size-medium wp-image-256" title="override-tab" src="http://www.sfcnmore.com/wp-content/uploads/2009/06/override-tab-300x214.jpg" alt="override-tab" width="300" height="214" /></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2009/06/open-tab-to-default-view/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Falling Behind</title>
		<link>http://www.force2b.net/index.php/2009/05/falling-behind/</link>
		<comments>http://www.force2b.net/index.php/2009/05/falling-behind/#comments</comments>
		<pubDate>Wed, 27 May 2009 10:03:08 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[Miscellaneous]]></category>

		<guid isPermaLink="false">http://www.sfcnmore.com/?p=249</guid>
		<description><![CDATA[OK &#8211; It&#8217;s been a while since I&#8217;ve had a blog post and it&#8217;s just starting to get on my nerves. As you might expect, it&#8217;s a time thing. Just not enough of it &#8211; Summer is coming, I&#8217;m out biking more, work has started to pick up. All good things, but still gotta find more time to blog again.]]></description>
			<content:encoded><![CDATA[<p>OK &#8211; It&#8217;s been a while since I&#8217;ve had a blog post and it&#8217;s just starting to get on my nerves. As you might expect, it&#8217;s a time thing. Just not enough of it &#8211; Summer is coming, I&#8217;m out biking more, work has started to pick up. All good things, but still gotta find more time to blog again.</p>
<p>In the mean time SalesForce.com is preparing to release Summer &#8217;09 (API 16) soon. Personally, I can&#8217;t wait. Looks like some very exciting new features are coming our way. The 100 page Release Notes document gives you an idea of the scope of the release. Lots of work in the API and the DaaS (Development as a Service) support. There are still some missing pieces in the Metadata API needed for true migration support, but they&#8217;re getting closer. Hopefully they&#8217;ll add in Metadata types for areas such as Lead Settings, Opportunity Settings, Big Deal Alerts, Assignment Rules, etc.</p>
<p>On the plus side, I just got my Zune back yesterday. It was out for warranty repair for a couple of weeks. Definitely missed it.</p>
<p>Hopefully I&#8217;ll have a chance to write up something good on the new Summer &#8217;09 release soon.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2009/05/falling-behind/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Mass Contact Transfer &#8211; Part 2 (The Controller)</title>
		<link>http://www.force2b.net/index.php/2009/04/mass-contact-transfer-part2/</link>
		<comments>http://www.force2b.net/index.php/2009/04/mass-contact-transfer-part2/#comments</comments>
		<pubDate>Mon, 20 Apr 2009 19:38:39 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[SalesForce.com]]></category>
		<category><![CDATA[Apex Code]]></category>

		<guid isPermaLink="false">http://www.sfcnmore.com/?p=236</guid>
		<description><![CDATA[Mass Contact Transfer for SalesForce.com - Part of a multi-part post on developing a visualforce page to allow for mass contact transfers within SalesForce.com]]></description>
			<content:encoded><![CDATA[<p><em><span style="color: #ff6600;">Click on the</span><strong><span style="color: #ff6600;"> <a href="http://www.force2b.net/index.php/source-code/">SourceCode</a></span></strong><span style="color: #ff6600;"><a href="http://www.force2b.net/index.php/source-code/"> </a>tab above to view the full sourcecode for the application or to install a complete working version into your environment.</span></em></p>
<p>In the last blog post I went into some of the details behind the Mass Contact Transfer VisualForce page. In this post, I’ll delve into the page Controller and supporting classes that contain the business logic for the page.</p>
<p>The transferContacts class is the controller for the VisualForce page. The controller has four main functions:</p>
<ul>
<li>Provide the get/set methods for fields used on the VisualForce page</li>
<li>Create picklists of users for the To and From user fields</li>
<li>A doSearch() method that looks for records based on the criteria entered</li>
<li>A doTransfer() method to transfer the selected contacts to the new users</li>
</ul>
<h3>Get/Set methods</h3>
<p>Generally these are very simple methods to either set the value of a public variable or return that value. Get/Set methods are always preceded by the word get or set followed by the name of the variable. On the VisualForce page these are referenced as {!fieldname}. For example, using value=”!fromUserID}” on a VisualForce page will call the getfromUserID() method to retrieve the value and setfromUserId() to set the value when the form is submitted.</p>
<pre>// Variables
public string fromUserID;
public string toUserID;

// Get/Set Methods for the FROM and TO UserID's
public String getfromUserID()   { return fromUserID; }
public String gettoUserID()     { return toUserID; }
public void setfromUserID(string userID)  { this.fromUserID = userID; }
public void settoUserID(string userID)    { this.toUserID = userID; }</pre>
<h3>The From and To User picklist fields</h3>
<p>Rather than require users to use a search lookup for users on the transfer form, I implemented this using two picklists for the From and To users. The FromUsers list includes all Users while the ToUsers lists only includes Active users. The setup behind the two picklists fields is very straight forward.</p>
<p><em>VisualForce page code for a picklist.</em> The codeblock below accesses the getFromUsers() method to fill the values in the  tag.</p>
<pre>&lt;apex:selectList value="{!fromUserID}" size="1" required="false"  id="fromUserID"&gt;
&lt;apex:selectOptions value="{!FromUsers}"&gt;&lt;/apex:selectOptions&gt;
&lt;/apex:selectList&gt;</pre>
<p><em>Apex Controller code to return the picklist of values.</em> The getFromUsers() method returns a List object of Users sorted by Name. The SelectOption list type accepts two values – an ID and a display name. When a FromUser name is selected from the list, the Apex Controller will be able to access the ID of that user by referencing the toUserID variable. This is set by the page to the ID of the selected when the form is submitted.</p>
<pre>public List&lt;SelectOption&gt; getFromUsers() {
    List&lt;SelectOption&gt; options = new List&lt;SelectOption&gt;();
    options.add(new selectOption('', '--- select a User ---'));
    for (User u : [Select ID, Name FROM User Order by Name]) {
            options.add(new selectOption(u.ID, u.Name));
    }
    return options;
}</pre>
<h3>Searching for Contacts</h3>
<p>The doSearch() method is called when the [Find] button is clicked on the page.</p>
<pre>&lt;apex:commandButton title="Find" value="Find" action="{!doSearch}"/&gt;</pre>
<p>The overall goal of the method is to build an SOQL string, run the Query, and display a list of contacts on the page. As discussed in Part 1, the searchCriteria() class contains the methods necessary to generate the actual WHERE clause parts to build the query string. The logic behind this is shown below.</p>
<p>To start, a base SOQL string is built selecting all the fields in the Contact object along with key fields from the Account, Owner, Account.Owner, CreatedBy.Owner, and LastModifiedBy.Owner relationships. The initial contents of the WHERE exclude Contacts where the current owner is the owner to transfer contacts to (in other words, they own the contacts already).</p>
<pre>// Build the base SOQL String, querying the standard Contact fields
// WHERE the current OwnerID = the selected value
string cSOQL = 'SELECT ' + contactFieldsList + ', Account.Name, Account.Site, Account.Owner.Name, '  +
'Account.Industry, Account.Type, Account.Owner.Alias, ' +
'Owner.Name, Owner.Alias, CreatedBy.Name, CreatedBy.Alias, LastModifiedBy.Name, LastModifiedBy.Alias ' +
'FROM Contact WHERE OwnerID &lt;&gt; \'' + toUserID + '\' ';</pre>
<p>If a To Owner was selected, add to the WHERE clause to restrict the list of contacts owned by the To User ID.</p>
<pre>// If a From User was selected, add this to the criteria
if (fromUserID &lt;&gt; null) cSOQL += ' AND OwnerID = \'' + fromUserID + '\' ';</pre>
<p>For each line of Criteria, call the BuildWhereClause() method in the searchCriteria class.</p>
<pre>// For each criteria line item, call the method to build the where clause component
for (searchCriteria cl : criteriaLine) {
cSOQL += cl.buildWhereClause(DebugMode);
}</pre>
<p>Finally, order the list by Account Name and then Contact Name and limit the list to the first 250 contacts.</p>
<pre>// Sort the results and limit to the first 250 rows
cSOQL += ' ORDER BY Account.Name, Name LIMIT 250' ;</pre>
<h3>searchCriteria class</h3>
<p>The BuildWhereClause() to build the WHERE clause component for each of the search criteria lines is where it got complex. This method had to generate code to handle different field types (Text, PickList, Boolean, Number, Date, DateTime, etc.), different operators (=, &gt;, &lt;, contains, IN, etc.) and different types of values. Most of the logic is fairly straight forward, checking the field type and the operator and generating errors where the two are not compatible (BOOLEAN and ‘Less Than’, for example).</p>
<p>The complex part of the logic is to handle Date and DateTime field types. The most recent version of the application now supports the date format of the current user when parsing the value entered. Where this became tedious was for DateTime types. For example, you might expect the following SOQL WHERE block to only retrieve Contacts created on April 1, 2009:<span style="color: #008000;"> WHERE CreatedDate = 2009-04-01</span>. However, CreatedDate is a DateTime field and requires a timestamp, not just a date. In order to properly query Contacts created on 4/1/09 the actual WHERE clause needs to looks like: <span style="color: #008000;">WHERE (CreatedDate &gt;= 2009-04-01T00:00:00Z AND CreatedDate &lt;= 2009-04-01T23:59:59Z)</span></p>
<h3>Transferring the Contacts</h3>
<p>The final step in the process is to transfer the selected contacts to the ‘To User’. The toTransfer() method starts by building a list of Contact ID’s for selected Contacts. Part 1 of this blog post goes into the checkbox on each Contact. Only checked contacts are transferred. The list of ID’s is passed to a Query to select the Contacts. Finally, the OwnerID for each Contact is changed and the Database.Update() method is called to do the actual transfer.</p>
<pre>// Build a list of Contact ID's to transfer ownership for
List&lt;string&gt; IDs = New List&lt;string&gt;();
for (transferContactSearchResults c : searchResults) {
if (c.selected) IDs.add(c.contact.ID) ;
}

// Query the contacts being transferred
List&lt;Contact&gt; contacts = [SELECT ID, OwnerID, Name, Account.Name, Title, Owner.Alias FROM Contact WHERE ID IN :IDs];
for (Contact c : contacts) {
c.ownerID = toUserID ;
}

// Process Errors and Count the Number of Records Transferred
Integer transferCount = 0;
List&lt;database.saveresult&gt; srs = database.update(contacts);
for (database.saveresult sr : srs) {
if (!sr.isSuccess()) {
      	ApexPages.AddMessage(new ApexPages.Message(ApexPages.Severity.FATAL, sr.getId() + '/' + sr.getErrors()[0].getMessage() ));
} else {
      	transferCount++;
      }
}</pre>
<p>At the very end, the doSearch() method is called to look for additional contacts if there were more than 250 returned in the first query call.</p>
<p>Quick links to Class source code:</p>
<ul>
<li><a href="http://sfdc-masscontacttransfer.googlecode.com/svn/trunk/Mass%20Contact%20Transfer/src/classes/transferContacts.cls" target="_blank">TransferContacts</a></li>
<li><a href="http://sfdc-masscontacttransfer.googlecode.com/svn/trunk/Mass%20Contact%20Transfer/src/classes/searchCriteria.cls" target="_blank">SearchCriteria</a></li>
<li><a href="http://sfdc-masscontacttransfer.googlecode.com/svn/trunk/Mass%20Contact%20Transfer/src/pages/transferContacts.page" target="_blank">VisualForce Page</a></li>
</ul>
<p>The final part of this blog post series will go into building the test class.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2009/04/mass-contact-transfer-part2/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Mass Contact Transfer &#8211; Part 1 (The Page)</title>
		<link>http://www.force2b.net/index.php/2009/04/mass-contact-transfer-part1/</link>
		<comments>http://www.force2b.net/index.php/2009/04/mass-contact-transfer-part1/#comments</comments>
		<pubDate>Thu, 02 Apr 2009 18:05:52 +0000</pubDate>
		<dc:creator>mgsmith</dc:creator>
				<category><![CDATA[SalesForce.com]]></category>
		<category><![CDATA[Apex Code]]></category>
		<category><![CDATA[VisualForce]]></category>

		<guid isPermaLink="false">http://www.sfcnmore.com/?p=181</guid>
		<description><![CDATA[Mass Contact Transfer for SalesForce.com - Part of a multi-part post on developing a visualforce page to allow for mass contact transfers within SalesForce.com]]></description>
			<content:encoded><![CDATA[<p>At my previous employer one of my regularly tedious tasks was to mass re-assign contacts based on various conditions. Many times it was as simple as a group of Accounts were transferred to new Account Managers and the default behavior of SalesForce.com is to only transfer contacts owned by the Account owner. The result would be a group of Contacts needed to be transferred manually. I handled these requests using an exported report of Contacts with Contact ID with Ron Hess’s <a href="http://wiki.developerforce.com/index.php/Members:Force.com_Excel_Connector" target="_blank">Excel Connector</a> to update the OwnerID column for the contacts.  <img class="aligncenter size-full wp-image-195" title="masstransfercriteria" src="http://www.sfcnmore.com/wp-content/uploads/2009/04/masstransfercriteria.jpg" alt="masstransfercriteria" width="634" height="238" /> Clearly this required a better way – and VisualForce provided the platform.  Creating the Mass Contact Transfer VisualForce page was for the most part fairly straight forward. It’s essentially a two part page:</p>
<ol>
<li>Search Criteria</li>
<li>Search Results</li>
</ol>
<h2>Building the Search Criteria Portion</h2>
<h3>Retrieving the From and To User ID’s.</h3>
<p>To simplify the process of selecting the From and To users, this was constructed using two picklist fields instead of two text fields with a lookup. The “From” picklist includes all Users – active or in-active; the “To” picklist only lists active users.   </p>
<pre>&lt;apex:pageBlockSection columns="3" id="UserSelection"&gt;
   &lt;apex:pageBlockSectionItem id="FromUser"&gt;
       &lt;apex:outputLabel &gt;Transfer From User:&lt;/apex:outputLabel&gt;
       &lt;apex:selectList value="{!fromUserID}" size="1" required="false" id="fromUserID"&gt;
            &lt;apex:selectOptions value="{!FromUsers}"&gt;&lt;/apex:selectOptions&gt;
       &lt;/apex:selectList&gt;
   &lt;/apex:pageBlockSectionItem&gt;
   &lt;apex:pageBlockSectionItem id="ToUser"&gt;
       &lt;apex:outputLabel &gt;Transfer To User:&lt;/apex:outputLabel&gt;
       &lt;apex:outputPanel layout="block" styleClass="requiredInput"&gt;
       &lt;apex:outputPanel layout="block" styleClass="requiredBlock"/&gt;
       &lt;apex:selectList value="{!toUserID}" size="1" required="false"  id="toUserID"&gt;
           &lt;apex:selectOptions value="{!ToUsers}"&gt;&lt;/apex:selectOptions&gt;
       &lt;/apex:selectList&gt;
       &lt;/apex:outputPanel&gt;
   &lt;/apex:pageBlockSectionItem&gt;
&lt;/apex:pageBlockSection&gt;</pre>
<p><img class="alignright size-thumbnail wp-image-185" title="Mass Contact Transfer - Required Field" src="http://www.sfcnmore.com/wp-content/uploads/2009/04/requiredfield-150x39.jpg" alt="Mass Contact Transfer - Required Field" width="150" height="39" />The tough part was getting the red required bar next to the “To” user field. You would expect that setting the Required attribute on the apex:selectList tag would tell SalesForce.com to use the standard red bar for the field, but that is not the case. Instead you have to wrap the field with an apex:outputPanel tag and have another apex:outputPanel tag within the first that closes itself. This code is highlighed above in red. The  syntax should work for any field that you want to show the SalesForce.com standard red bar to indicate a required field.</p>
<h3>Search Criteria Section</h3>
<p>Next was to build the Selection Criteria section of the page. Initially it was very simple. I wanted five lines for selection criteria to match the standard Transfer pages. The first draft of the page had five repeated blocks of code in the VisualForce page for the Selection Criteria (field, operator, value). Clearly this was not the most efficient way to write the page, but it gave me a feel for the look and what was needed. The more efficient way  is to use a separate class for Selection Criteria. The Page Controller constructor method creates a List with 5 instances of the searchCriteria class and the VisualForce page can use an apex:DataTable tag to display however many rows are in that list. The resulting page looks like this:</p>
<pre>&lt;apex:dataTable value="{!searchCriteria}" columns="3" var="criteria"&gt;
   &lt;apex:column&gt;
      &lt;apex:selectList value="{!criteria.searchField}" size="1" id="SearchField" &gt;
        &lt;apex:selectOptions value="{!searchFields}"&gt;&lt;/apex:selectOptions&gt;
      &lt;/apex:selectList&gt;
   &lt;/apex:column&gt;
   &lt;apex:column&gt;
      &lt;apex:selectList size="1" value="{!criteria.searchOperator}" id="SearchOperator1"&gt;
        &lt;apex:selectOptions value="{!criteria.OperatorSelectList}"&gt;&lt;/apex:selectOptions&gt;
      &lt;/apex:selectList&gt;
   &lt;/apex:column&gt;
   &lt;apex:column&gt;
     &lt;apex:inputText size="20" id="SearchValue1" value="{!criteria.searchValue}"/&gt;
   &lt;/apex:column&gt;
&lt;/apex:dataTable&gt;</pre>
<p>The searchCriteria class itself provides the standard get/set methods for the three columns:</p>
<ul>
<li>searchField: The searchFields() method generates a selectList of fields in the Contact, Account, Contact.Owner, and Account.Owner objects.</li>
<li>searchOperator: The searchOperators() method returns a fixed selectList of operators – equals, not equals, etc.</li>
<li>searchValue: A simple inputText field to capture the search criteria value.</li>
</ul>
<p><img class="aligncenter size-full wp-image-196" title="selectioncriteria" src="http://www.sfcnmore.com/wp-content/uploads/2009/04/selectioncriteria.jpg" alt="selectioncriteria" width="567" height="132" /> When the user clicks the [Find] button on the page, the Page Controller Class is able to loop through the criteria lines and process each one individually. Since the Search Criteria section is written to be independent of the “Mass Contact Transfer” page, there is a method in the searchCriteria class to build the Where clause portion. The doSearch() method in the Page Controller Class appends each of the Where clause parts together to create a single SOQL statement to query the contacts based on the From UserID, To UserID, and user defined criteria. The Query is run and the results are appended to a searchResults List for display.</p>
<h2>Search Results</h2>
<p><img class="aligncenter size-full wp-image-223" title="Mass Contact Transfer Search Results" src="http://www.sfcnmore.com/wp-content/uploads/2009/04/searchresults.jpg" alt="Mass Contact Transfer Search Results" width="569" height="124" /></p>
<p>At the bottom of the page there is a section that starts as hidden using the style attribute on the apex:outputPanel tag. {!ShowBlockIfResults} returns either “display: block;” to show the block (only if there are search results) or “display: none;” to hide the block.  In the list of Contacts, a checkbox in the first column is used to allow the user to select which contacts should be transferred. This is checked by default. To simulate how the standard SalesForce Transfer pages work, the user can check or uncheck all Contacts by clicking the checkbox in the column header. This is accomplished using some simple JavaScript code linked to onClick event on the checkbox in the column header. The styleClass, rowClasses, onrowmouseout, and onrowmouseover attributes of the apex:DataTable tag are used to format the results table so it looks like the standard SalesForce Transfer pages.</p>
<pre>&lt;apex:outputPanel id="Results" layout="block" style="{!ShowBlockIfResults}"&gt;
&lt;apex:form id="resultsForm" &gt;
  &lt;apex:pageBlock id="resultsBlock"&gt;
  &lt;apex:pageBlockButtons &gt;
      &lt;apex:commandButton title="Transfer Selected" value="Transfer Selected" action="{!doTransfer}"/&gt;
  &lt;/apex:pageBlockButtons&gt;
      &lt;apex:dataTable value="{!searchResults}" var="Results" id="resultsDataTable"
      styleClass="tableClass list" rowClasses="odd,even"
      onrowmouseout="if (window.hiOff){hiOff(this);}" onrowmouseover="if (window.hiOn){hiOn(this);}"&gt;
        &lt;apex:column &gt;
          &lt;apex:facet name="header"&gt;&lt;apex:inputCheckbox id="selectall" selected="true"
              onclick="javascript:customSelectAllOrNoneByCheckbox(document.forms['MassTransferContactsPage:resultsForm'],'MassTransferContactsPage:resultsForm:resultsBlock:resultsDataTable:', this);"/&gt;&lt;/apex:facet&gt;
          &lt;apex:inputCheckbox value="{!Results.selected}" id="selected" /&gt;
        &lt;/apex:column&gt;
		…. DataTable Columns go here ….
      &lt;/apex:dataTable&gt;
   &lt;/apex:pageBlock&gt;
&lt;/apex:form&gt;
&lt;/apex:outputPanel&gt;</pre>
<p>Finally, when the user clicks the [Transfer Selected] button, the doTransfer() method on the Page Controller loops through the searchResults list to build a list of Contacts whose OwnerID should be changed. Any errors in the Database.Update call are displayed in the messages section at the top of the page. The last step is to re-run the doSearch() method to query any remaining contacts not transferred the first time (if they were not checked, there was an error, or the original query returned more than 250 rows).</p>
<p>Next week, Part 2 of this blog post will go into the Apex code in the Page Controller and the two supporting classes.  In the mean time you are welcome to download the source code or install the AppExchange package by clicking on the <a href="http://www.sfcnmore.com/index.php/source-code/" target="_self">SourceCode</a> tab at the top of the page.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.force2b.net/index.php/2009/04/mass-contact-transfer-part1/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
	</channel>
</rss>
