Friday, December 9, 2011

Simile Timeline in Salesforce, Revisited

The Simile Timeline is a javascript widget that's available as open source to create interactive timelines.  If you go to the main page for the Simile Timeline, you'll see how you can drag the timeline back and forth through time and click on items to see a detailed description; it's pretty slick.

Back in another life, I had implemented this timeline in Salesforce to provide a graphical display of a Contact's history on their detail page: Events, Tasks, (Job) Opportunities, Interviews, Jobs.  I did it by customizing the free Timeline S-control mashup that utilizes that Simile Timeline widget.  It provided a nice graphical narrative that you could scroll forward or backward in time through, and clicking an individual item on the Timeline would display details on and a link to the record.  This is the screenshot of that application from the appExchange:

That application is still available, but in it's original S-control form, now replaced by Visualforce.  Salesforce still supports S-controls, so you can  use it if you're fine with the default configuration it comes with.  If you're going to need to customize the information that's displayed on the timeline, for instance showing custom object child records to Account, Contact, Case or Opportunity or values of custom fields in the pop-up details, I'd recommend just doing this in Visualforce, which is what I've just done for a client.  Anyone with a bit of javascript and Apex savvy can easily implement this themselves.

I'm considering creating a nifty little package that anyone can install to implement it with no code, probably with an admin screen to let Sys Admins select the Timeline settings such as the intervals of time displayed, and a query interface to display custom object records or fields without requiring any code.  Interested?  Leave me a comment.

Not being an asshole wins the race...

Having a tortoise as a pet, I often think of the Tortoise and the Hare fable.  The sum up of that story is "slow and steady wins the race".  The tortoise didn't win because he was slow and steady, he won because that hare was an asshole.  To me, that's a much more important lesson than slow and steady- being an asshole can bite you in the ass.  And that's exactly how you should explain that to your children.  I only wish that were a more predictable outcome. 

My tortoise is very cute; he even likes to snuggle with me-

Still don't think he's cute?  How about this?

What I've really learned from Rokku is determination.  That boy will not give up.  When I take him out on the terrace, 7 flights up, he sometimes gets it into his head that he would like climb over the edge and see what's out there.  I've tried to explain to him that that would be suicide.  I pick him up and move him away, he scrambles right back.  The more you pull him away from his perceived destination, the harder he will try to get there.  Rokku, stop burrowing into those electrical cables!  It's admirable if not nerve-wracking, and I love him for it.

Monday, December 5, 2011

Oh how I loves me some zombie violence

I've discussed this on Friendface and with friends, but figured I'd include my thoughts on it here as an insight into the minds of people.  I was originally going to say it was an insight into my mind, but this is one of those commonalities that brings us together as a species.

There are certain movies and books with scenes of brutal violence against humans (or humanoids) to which we are very much drawn, and zombies stories are a prime example.  I'm also always up for some Nasi violence too.  Our lizard brains get a thrill from violence, it's deep within us from millions of years of  evolution as meat eaters and territorial beasts.  But our rational minds tell us that we can't just go around slaying and beating at will (well, some of us anyway).

Zombie and Nasi violence presents us with the rare opportunity to enjoy a healthy dose of violence with the moral quandry removed.  Storytellers have long been aware of this; it's why they go to lengths to build up the evil qualities of a character before presenting us with their gruesome death.  The more they've worked to show you just how evil someone is, the more painful, gory detail you can expect in their last moments.

Here's a list of some human(oid)s for whose demise I will cheer (did I un-dangle that participle correctly?).  I'll admit that it gets a little ethically questionable towards the end.
  • Zombies
  • Nasis (becoming an over-used antagonist in movies again)
  • Khmer Rouge party leaders (an under-used antagonist in movies that I vote to now replace Nasis)
  • Aliens plotting the destruction of our planet, as implausible a concept as I find this to be
  • Conquistadors
  • Serial killers (or single instance killers, depending on the circumstances)
  • Child rapists
  • Oh, any rapists really
  • Followers of Sauron
  • Software agents posing as humans in a virtual reality created to control humans and use us as batteries, as implausible a concept as I find that to be
  • Anyone who shouts "Death to America!" (hey, I'll be the first to admit our imperfections, but fuck you, man)
  • Anyone Dick Cheney has ever trusted to do his dirty work
  • Dick Cheney
  • Hedge fund managers
  • Executives at companies that implement hydrofracking (I've been a little fixated on this lately.  I like water)
And let's be clear, I'm not speaking about this in terms of death penalty legislation, on which I have a completely different stance, or sanctioning rampant murder sprees of people who fit these descriptions, which would put you squarely in the serial killers category.  This is purely regarding the mutilation and death of fictional characters for my entertainment.  But nonetheless, I accept the impact this will have any future runs for office.

Sunday, December 4, 2011

Why won't this damn thing reRender properly...

Since Visualforce came into being, the aspect of it I've had the most trouble with is the reRender, or more specifically, getting reRenders to behave the way I want them to.  This is partly because much of the coding I did before Salesforce was behind the scenes logic and not web interface design, but it's partly because reRenders can be a real pain in the ass.  Along the way, I've figured out some tips and thought I'd share.

actionRegion
You will drive yourself insane with reRenders if you don't know how to use actionRegions. actionRegions are to submitting what reRenders are to rerendering.  Perhaps a little more explanation and a demo are in order.

When you perform any action on your VF page, by default the entire form is submitted.  You may not actually need everything submitted though; you may just be need a portion of your variables submitted, or maybe none at all.  Submitting everything needlessly means that not only are you slowing down performance of your page, but the page is attempting to validate what's being submitted before it sends anything back to the controller.  So if you have any required inputFields, for instance, those fields will need to be filled in before the form submits at all.  And if you don't know that's what's happening, either because your form has no <apex:pageMessages/> or it's not being reRendered, it will appear as if your action isn't working for no reason at all. 

Let's use this simple page and controller as an example, first without an actionRegion (incorrect):
Page before adding actionRegion (the wrong way)
<apex:page standardController="Account" extensions="extTest">
    <apex:form >
        <apex:pageBlock>
            <apex:pageBlockButtons >
                <apex:commandButton value="Show Billing Street" reRender="opBilling">
                    <apex:param value="true" assignTo="{!ShowBilling}"/>
                </apex:commandButton>
            </apex:pageBlockButtons>
           
            <apex:pageBlockSection >
                <apex:inputField value="{!Account.Name}"/>
            </apex:pageBlockSection>
           
            <apex:outputPanel id="opBilling">
                <apex:pageBlockSection rendered="{!ShowBilling}" id="pbMailing">
                    <apex:inputField value="{!Account.BillingStreet}"/>
                </apex:pageBlockSection>
            </apex:outputPanel>
        </apex:pageBlock>
    </apex:form>
</apex:page>
 Extension:
public with sharing class extTest {
    public Boolean ShowBilling {get;set;}
   
    public extTest(ApexPages.StandardController controller) {
        ShowBilling = false;
    }

}
The idea is, the page opens showing only the Account Name field. Clicking the Showing Billing Street button will update the ShowingBilling variable to true and reRender the opBilling outpanel so the Billing Street field is displayed.  As it's written above however, it will not work if the Account Name field isn't filled in first.  That Name field is required, so the command button tries to submit the whole form and it fails validation without a Name value entered.  Since only the opBilling outputPanel is being reRendered, you won't event see an error message since pageMessages isn't being reRendered (Debug logs are your friend when troubleshooting such issues).

One way to fix this is by updating the page with an actionRegion around the commandButton like so:
pageBlockButtons after adding actionRegion (one right way)
<apex:pageBlockButtons >
                <apex:actionRegion >
                    <apex:commandButton value="Show Billing Street" reRender="opBilling">
                        <apex:param value="true" assignTo="{!ShowBilling}"/>
                    </apex:commandButton>
                </apex:actionRegion>
 </apex:pageBlockButtons>
Now with actionRegion around that button, only the values inside of the actionRegion are submitted, so BillingStreet will be rendered with or without a value in the Account Name field.

Immediate
For the sake of keeping the example above simple, the button didn't do anything other than updating ShowBilling using the param tag and reRendering opBilling.  In reality, you'd only need actionRegion when you need some portion of the variables on the page submitted to the controller/extension to perform logic in a method.  If you don't need to submit any variables, then you can use the "immediate" property of the tag that's performing an action.  Let's see this with the example above:
pageBlockButtons after adding immediate (another right way)
<apex:pageBlockButtons >
                <apex:commandButton value="Show Billing Street" immediate="true" reRender="opBilling">
                    <apex:param value="true" assignTo="{!ShowBilling}"/>
                </apex:commandButton>
</apex:pageBlockButtons>
Make sure you know what immediate means before using it. I've seen people set immediate to true to avoid issues with required fields not realizing that their controller/extension was not receiving any updated variable values from their page, thereby screwing up their logic and leaving them flummoxed.

Choosing what to reRender
I'll probably expand on this in a separate post because there are a lot of scenarios to consider, but I'll use the example above to give one basic tip. 
You may have noticed in my example that I've surrounded the pageBlockSection that contains BillingStreet with an outputPanel, and the reRender acts on that outputPanel.  This may seem like an extra component- why not just reRender the pageBlockSection itself and skip that outputPanel altogether?

What I've learned is that if a reRender updates a variable on your page, you need to reRender a parent of the tag that contains that variable, and not the tag itself. OutputPanels are a useful means of doing so.  To see this in action, try updating the example above so the button attempts to reRender the pageBlockSection directly:
pageBlockButtons with reRender of the pageBlockSection (wrong way)
<apex:pageBlockButtons >
                <apex:commandButton value="Show Billing Street" immediate="true" reRender="pbMailing">
                    <apex:param value="true" assignTo="{!ShowBilling}"/>
                </apex:commandButton>
  </apex:pageBlockButtons>
If you try this example with the commandButton set to reRender the pageBlockSection, it just doesn't work.  So either you need that outputPanel surrounding the pageBlockSection, or alternatively you could move the rendered="ShowBilling" property to the inputField instead, but in this example, that would mean you're rendering an empty pageBlockSection.

As above, there are more scenarios to explore here, but I'll leave it at this for now and hopefully this is helpful to people frustrated with the nuances of reRendering.

Gettin' all meta about my blog

For awhile I've had two blogs going, the long out of date Enlightened Platypus for technical posts and Recipes of a Platypus.  I also had a Friendface account to appease my egotistical desire to spout my views off to the world.  I've now shunned Friendface and realized that I might as well merge all of my spoutings into a single blog.  For those of you only interested in my technical posts, largely Salesforce related these days, you can select that tab above.  Same for those of you interested in what I'm cooking these days, the Recipes tab is for you.  And for those of you actually, dare I say inexplicably, interested in what I babble on about (hi Mom and Dad!), then Personal is for you. And now the question is, what to do when the day comes that I shun Google?  We shall cross that bridge if and when we get there.

That will be all, carry on about your business.