Trapdoor In The Sun

Alan Shanahan, Technician & Consultant


Leave a comment

Force.com: Visualforce; slightly better field declarations

Soft coded = good. Hard coded = bad. That’s difficult to argue against and I doubt there’s much dissent in any programming community.

Define it once, use it many times; this is part of the reusability principle that applies to code segments and text literals. When you define an input field in a Visualforce page, more often than not it is based on a field that exists somewhere in the database. It makes a whole lot of sense to take as many attributes from the original field definition as possible, so below are some examples of how you might do that.

(1) When defining a field on a page, prefix it with its label. Use this syntax:
$ObjectType.ObjectName__c.Fields.FieldName__c.Label
…where ObjectName__c and FieldName__c should be replaced as appropriate.

(2) Use the field’s own help text by referring to the InlineHelpText attribute, as shown below in this syntax:
$ObjectType.ObjectName__c.Fields.FieldName__c.InlineHelpText
…where ObjectName__c and FieldName__c should be replaced as appropriate.

(3) Limit the field length in HTML during data entry by using this syntax:
$ObjectType.ObjectName__c.Fields.FieldName__c.Length
…where ObjectName__c and FieldName__c should be replaced as appropriate.

<apex:pageBlock id="searchPageBlock">

	<apex:pageBlockSection columns="2"
	 id="searchPageBlockSection" title="Global Search" collapsible="false">

		<apex:pageBlockSectionItem id="searchAirport"
		 helpText="{!$ObjectType.Airport__c.Fields.Airport_Name__c.InlineHelpText}">

			<apex:outputLabel
			 value="{!$ObjectType.Airport__c.Fields.Airport_Name__c.Label}" />
			<apex:inputText
			 value="{!wrkAirportName}"
			 tabIndex="2"
			 id="inpAirportName"
			 maxlength="{!$ObjectType.Airport__c.Fields.Airport_Name__c.Length}"
			 onkeypress="return noenter(event);" />

		</apex:pageBlockSectionItem>
	</apex:pageBlockSection>
</apex:pageBlock>

The above code works well for text input fields. If you need information on numeric or other input field types check out the $ObjectType schema information page.

Advertisements


4 Comments

JustCloud.com – A Comedy Lesson

An online purchase I made towards the end of last year back put me in mind of an episode of The Office (US) where the Michael Scott Paper Company realised that it was selling paper at unsustainable prices; Michael himself rang a customer to ask them to pay more. The goods had already been paid for and delivered.

After much soul searching and consideration, I have decided to publish details of this episode.

For ages I had been searching for a reasonably-priced way to safely store my large personal photo and video collection in a cloud-based, secure location to protect me from the usual fears: fire, flood, damage, theft, hacker sabotage, pestilence and plague. I stumbled across JustCloud.com, and this seemed to provide the solution I needed, and the special offer seemed to be great value.

After two weeks of uploading my >500GB collection, I was a little happier that I was covered. I paid up front for 2 years so I got Unlimited storage for EUR 166.85. UNLIMITED. Their word, not mine.

JustCloud.com Backup External Drives

A few weeks later I was looking at application screens telling me I had to upgrade to keep the same service I was already using and had paid for. So I looked carefully at this in order to understand why; the three USB hard drives I kept permanently connected to my machine were the reason – suddenly, JustCloud decided I had to pay more for backing them up. But they decided this unilaterally and without warning. The amount they were demanding (also by email, by the way) was EUR 239.85 – far in excess of my original two year payment, and this was on top of my original payment.

I don’t need to tell you how or why this is wrong, and why I then demanded my money back, in full, without delay. I would have gladly have taken them to court for breach of contract for their nefarious practices, were it not for the complex, costly and time-consuming aspects of legal jurisdiction. I live in Ireland, they are based in the UK. But I would have dearly loved to have taught them a lesson.

Here is a snapshot of my initial angry email, sent in response to first discovering their trickery:

Message: Support,
Having signed up to JustCloud and having used it since around August 10th,
I now find that it is asking me for an additional EUR79.95 per external
drives. Drives that it has been backing up since the start of my subscription.
This is absolutely outrageous. You cannot change the terms of business part-way
into my subscription. Unless this is rectified very quickly, I will expect a
full refund of all monies paid and removal of all of my private files from your
backup servers.

Their answer to this was of the cut-and-paste variety, and almost passive-aggressive in its tone. And what angered me further was that they seemed to be completely ignoring my point – that they can’t just make it up as they go along.

Hi Alan,

I am sorry to hear you wish to cancel.

The last thing we don't want to frustrate our customers, we had to put these
additional charges in place to keep running our subscriptions at such a low price.

As a valued customer we would be happy to offer you the Video Backup ***and/or*** Files
over 1GB add-on for free.

I just want to clarify that it is still possible to Drag & Drop or right click on
a file that is anywhere of any type and back it up without these additional services.

Please confirm how you want to proceed.
--
--
XXXXXX XXXXXXXX
User Experience Team
www.JustCloud.com

But to tell me that they “…had to put these additional charges in place to keep running our subscriptions at such a low price” – a startling tacit admission that they were, in fact, making it up as they went along. There’s the court case winner right there, in a single sentence.

My next email was this:

The one thing you are doing, at least in this case, is frustrating a
customer. It's fairly outrageous that you can decide to move the goalposts
and tacitly admit to breaking your contract. Clearly, I am not a valued
customer as you have just asked me to fork out an additional EUR 240 per
year for the service you have already agreed to provide to me. It's not my
fault your company has not properly costed its offering.

Also, do you see the ridiculous irony in charging a *lot* more in order to
"keep running our subscriptions at such a low price"? This is management
speak at its worst and I'm not falling for it.

Please cancel and refund my subscription payment, in full, as soon as
possible. And please remove my backed up files from your servers. I will
report this to Visa if my refund is not complete, to the penny. And I will
get it too. I paid for two years up front. You really have quite a cheek
forcing me to pay more, at this point, to get the same service you
contracted with me to provide.

I will now have to look again for an alternative replacement service, and
for a service that is somewhat more trustworthy. I expect this behaviour
will damage your business, and I don't care if it does. I will
also take steps to warn those friends of mine I had already recommended your service
to of this experience. And I will make a larger audience aware of it too.
This sort of nefarious practice will simply not stand.

Sincerely
Alan Shanahan

After a couple of days I checked my credit card statement and saw that they had refunded me all of my payment, less approx. EUR 13 which I can only presume they kept to pay for using their time in responding to my emails. Call me a coward, but I couldn’t be bother going through the admin headache of chasing it.

By chance, I came across this Facebook page: Avoid JustCloud

I was not alone. It’s a fair assumption that you will only ever hear of a small percentage of unhappy customers, because many people will not take it upon themselves to chase these things up, complain openly or to join such unhappy public forums.

It’s outrageous that a subscription business thinks this type of nefarious practice will stand: simply because they cannot accurately build a cost model into their business. Getting a small minority of (potentially) loyal customers to pay for their business risks is no way to guarantee business survival; if anything, it’s only going to help guarantee failure. Do we really have to return to Business 101 by stating that the most important asset of a business is NOT its people, it is the CUSTOMERS? For the record, I actually annoyed myself typing that.

There are some damning reviews at this link: C|Net user reviews of JustCloud

I could continue to bore you with the subsequent relentless emails I got from them – almost as if none of this had happened – but I won’t. An automated marketing engine totally lacking in intelligence or any form of personal touch, all of which was glaringly obvious.

I wonder how much of my recurring business they lost. And how many lost referrals, on my part. And who will read this and decide not to use them? That’s one hell of a business strategy.

My message to the owners of JustCloud: Unless your business is comedy, don’t let comedians run your business.


4 Comments

Force.com: Visualforce programming, position cursor at first input field

When building a custom Visualforce page with input fields, one common requirement is to place the cursor at the first input field on the page. You would think this would be a simple matter and Salesforce itself manages the task quite well. But when the platform’s default behaviour kicks in and overrides your page’s behaviour, it doesn’t always work smoothly. Or if you want to position on an input field that is not a text entry field it doesn’t always slide into place. Or perhaps you wish to show a dialog box where you wish to conditionally position the cursor to a Confirm or Cancel button depending on prior processing.

In this piece, I’m offering a foolproof way to enable your page to behave exactly as you want it to, in an easy, maintainable way. Here is the step by step way to do this.

First, download a copy of the JQuery library from jquery.com. The minimised (compressed) version is just fine.

Now, upload it to your Salesforce org as a Static Resource.

In your Visualforce page, add this line somewhere after the apex:page tag:

<apex:includeScript value="{!$Resource.JQueryJS}" />

…making sure to replace the JQueryJS text with the name you specified during the Static Resource upload step.

The code below assumes that the page is aware of a “mode” or action passed to it, perhaps as a querystring parameter and parsed separately into a variable called wrkAction.


...

	<script language="JavaScript">

	//----------------------------
	// JQuery initialisation
	//----------------------------
	j$=jQuery.noConflict();
	j$(document).ready(function() {
		initialisePage();
	});

	//-------------------------
	function initialisePage() {
	//-------------------------
		positionCursorToFirstField();
	}
	//-------------------------------------
	function positionCursorToFirstField() {
	//-------------------------------------
		if ('new' == '{!wrkAction}' || 'edit' == '{!wrkAction}' || 'copy' == '{!wrkAction}') {
			j$("[id*=':btnConfirm']").focus();
		}
		if ('del' == '{!wrkAction}') {
			j$("[id*=':btnCancel']").focus();
		}
	}
	</script>

The page buttons might be defined later in your page code, as follows:

	<apex:pageBlockButtons id="pbButtons" location="bottom">
		<apex:commandButton id="btnCancel"  value="Cancel"  immediate="true" onclick="return checkCancel();"  />
		<apex:commandButton id="btnConfirm" value="Confirm" immediate="true" onclick="return checkConfirm();" />
	</apex:pageBlockButtons>

Given that any page element will probably exist in the hierarchy of page elements, the Visualforce page is rendered with the implicit force.com naming applied i.e. the full “pathname” to the element is implied in the name, with colons separating each branch in the tree. For example, an HTML id such as j_id0:j_id1:j_id192:j_id193:j_id196:j_id230:j_id231:j_id232:4:j_id236 would not be unusual.

The above code brings a “best practice” tip to mind – always use page-unique ID values for input fields, buttons and all other page components. Specifying the ID tag also ensures that the force.com implicit naming conventions are not applied.

The JQuery code in the positionCursorToFirstField javaScript method above provides a major advantage: you are now effectively freed from having to worry about the naming hierarchy. The JQuery selector finds the field ending with a colon character followed by the specified unique fieldname. This also means you can move it around on the page and within the page element hierarchy (DOM) and not have to worry about this code failing or needing to be modified.

There’s just one more piece of code needed to ensure the force.com standard processing doesn’t happen i.e. that the platform itself doesn’t try to be too clever and preempt what you’re trying to do. This code masks the effect of the standard “first input field positioning” processing:

	<script language="JavaScript">

	//--------------------------------------------------------------------------------------------------------------
	// This empty function overrides the SFDC standard function, and enables us to control initial field positioning
	//--------------------------------------------------------------------------------------------------------------
	function setFocusOnLoad() {
	}

	</script>