Showing posts with label Visualforce. Show all posts
Showing posts with label Visualforce. Show all posts

Monday, May 1, 2017

getValue() getter method vs. { get; } shorthand

Salesforce's { get; set; } syntax has been around for a long time and is a time-tested, reliable way to define properties in Apex. But after testing its usability and limitations in Spring '17,  I've decided that explicitly declaring traditional getter and setter methods should be preferred over using the convenient { get; set; } syntax.

The primary reason is that the only way to expose a property in a custom Apex class for use with Lightning Components is to use the @AuraEnabled annotation, and this annotation only works on a traditional getter method such as String getName().

The secondary reason is that the developer also has the option to either call the getter or access the private field directly from other methods in the class, which is not possible when using { get; set; }.

Monday, January 11, 2016

6 Reasons You Got the Generic Error Page

Sometimes in Visualforce, you'll have debug logging enabled for a community or portal user, but loading a page fails with no trace of what went wrong. When you look in the debug log for an explanation, all you see is that Salesforce successfully loaded the Generic Error Page configured for the site.


Before logging a case or asking a fellow developer for help, check for the following 6 common culprits.

  • Are you missing any static resources, {!$Resource.__}?
  • Are you missing any custom labels, {!$Label.__}?
  • Are you missing any custom permissions, {!$Permission.__}?
  • Are you missing any page references, {!$Page.__}?
  • Are you missing any custom controller/extension properties bound on the page? This can be a problem when deploying packages among sandbox orgs.
  • Are you missing any custom controller/extension actions bound on the page?

What I've also discovered, interestingly enough, is that for some reason using MavensMate v6.0.0 with Sublime Text 3, saving a Visualforce page or component skips the validation for global variables used in Visualforce.

Friday, January 9, 2015

$Action.Contact.AddToCampaign explained

Recently a question came up about using $Action.Contact.AddToCampaign on a Visualforce page. The common usage pattern below for $Action variables does not work as expected.

So, I logged a case with Salesforce to get an explanation for how $Action.Contact.AddToCampaign is supposed to work. And the eventual answer I received after three weeks was very surprising.

In short, the merge variable only works when used as the action value in a form element. Let me illustrate this with the sample Visualforce code below.

The unfortunate answer at this point seems to be that $Action.Contact.AddToCampaign only works if you want to use it inside a custom HTML form, not an apex:form. salesforce.com's recommendation is to use $Action.Campaign.AddCampaign instead, which in my opinion defeats the purpose of easily launching a native wizard to add the contact in a given context to a user-specified campaign.

Sunday, December 21, 2014

Where's the Visualforce viewstate coming from?

I felt inspired by a Q&A on Salesforce Stack Exchange to explore the growth of viewstates in Visualforce under different conditions. Without even reaching all of the test cases I originally set out to investigate, I was extremely surprised by my initial findings:

  • A viewstate only gets created once an apex:form is added to the page, regardless of what controller, if any, is used; but more curiously...
  • A viewstate grows when non-form elements outside the apex:form are added to the page! How? And why?


So while I wait for a response from the case that I'm going to log with Salesforce Support, I welcome anyone else's explanation for this phenomenon. Below are the Visualforce pages that support my findings above.

Visualforce viewstate exhibits
Number Title Observations
Exhibit 1 No controller, no form No viewstate
Exhibit 2 Standard Lead controller, no form No viewstate
Exhibit 3 Custom controller with persistent property, no form No viewstate
Exhibit 4 No controller, one form There's a viewstate! Which seems odd, since there's no controller to process the viewstate.
Exhibit 5 No controller, two forms There's a single viewstate that's slightly larger than what's in Exhibit 4.
Exhibit 6 No controller, two forms There's a single viewstate that's slightly larger than what's in Exhibit 5, even though literally nothing has changed except for the addition of a new p element outside of the apex:form!

I've posted the source code for the Visualforce pages to GitHub as a gist.

Friday, November 21, 2014

Login with Facebook for a community with Visualforce

Adding an auth provider (e.g., Login with Facebook) to a Salesforce Communities instance is pretty easy.


The Login with ... button is pretty magical: It knows what community you're logging into, and it knows what URL you're trying to access upon authentication. Based on that information when you click the button, you're taken to the correct authentication URL based on the Auth Provider configuration in Salesforce.

But... for orgs that have customized their login pages with Visualforce, how do you add this button? Luckily, adding the same magical button to a custom Visualforce login page doesn't require you to manually reconstruct the OAuth authentication endpoint. Instead, you can just use the AuthConfiguration.getAuthProviderSsoUrl() method.

Simply put, you need just three things:
  • Your community's base URL
  • The relative path after the base URL to which the user should be taken upon successful authentication. This is also known as the startUrl.
  • The URL Suffix (a.k.a. DeveloperName) of your auth provider (e.g., Facebook) as configured in Salesforce

Once you have this information, all you need to do is create an action in your Apex controller that returns a PageReference object, constructed from the URL returned by AuthConfgiuration.getAuthProviderSsoUrl().


This same approach can be applied to other auth providers as well, such as Twitter or Google.

AuthConfiguration.getAuthProviderSsoUrl(String, String, String) explained

Curious about AuthConfiguration.getAuthProviderSsoUrl(String, String, String)? Here are some notes about the parameters that may not be apparent the first time you read the documentation.

String cUrl


You'll want this to match exactly what you see when you're looking at your community's Administration Settings. Don't add any extra trailing slashes!


String startUrl


This should be the URL relative to the value you put for cUrl, including the leading forward-slash ('/'). For example, if you want to land the user at the Home tab, startUrl should be set to "/home/home.jsp" (again, note the inclusion of the leading forward-slash).

Think about it this way: If you concatenate cUrl and startUrl, exactly as written, you should end up with a valid URL to the desired page or resource within your community.

String developerName


This is the DeveloperName field from the AuthProvider object. Or, you can find the value by looking at the URL Suffix field on the Auth Provider detail page.


You can find this value dynamically by querying the AuthProvider object.

Friday, October 10, 2014

Invalid apex:attribute name values

The apex:attribute component in Visualforce allows developers to pass custom Apex class instances as attributes from the parent component or page to the child component. In this manner, it's possible to pass a page controller itself as an attribute to a component on the page, using a simple self property like the following.

public CustomController getSelf() {
    return this;
}

What the documentation doesn't say is that apparently (at least in Winter '15, API 32.0) there are keywords to avoid when naming your attribute, even though the Visualforce parser will not tell you there's a problem.

Trying to name your attribute "controller" will cause something like the following error to appear when saving a page: Wrong type for attribute <c:buggersitepaypalcheckout controller="{!self}">. Expected BuggerSiteSimpleSelfRegController, found String



Trying to name your attribute "parent" will cause a completely blank error message to appear when saving a page. But it's an error that will prevent you from saving your page, nonetheless.



Do you know any other hidden no-no's with naming apex:attribute elements? Please share so that we can all avoid these frustrating quirks int he future.

Monday, September 22, 2014

Your request cannot be processed at this time. The site administrator has been alerted.

In setting up and testing self-registration for a new community built on Salesforce Communities, you may encounter this confounding error: "Your request cannot be processed at this time. The site administrator has been alerted."

"Alerted" in the above statement refers to an email alert that went out to the site administrator. But who is the "site administrator"? You can find the email address used for this notification by locating the Site Guest User for your community's Force.com site.
  1. Open Setup > Manage Communities
  2. Click Force.com for the community in question
  3. Click Edit
  4. Change Site Contact to the user who should receive notifications when errors arise with self-registration. Make sure the user's email address is valid.


For sandboxes, make sure your Access to Send Email is set to "All email", under Setup > Email Administration > Deliverability. (Thanks Lynnet!)


Below are a few common reasons why you may be encountering the problem:
  • The community is not published. In case you're working with a community that is offline or in Preview status, you need to publish the community before self-registration will work.
  • The Account Owner does not have a User Role assigned. If you're creating a new Account record on the fly, especially in B2C situations, you need to make sure you assign a default account owner that also has a User Role value. Any role will do, and you can use either a workflow rule or Apex to perform the assignment.
  • The site guest user does not have Create and Read permissions on the Account and Contact objects. Edit Public Access Settings for the community's Force.com site to grant these permissions, along with field permissions for any fields that are included on the self-registration form. Note that by default the site's profile will not have these permissions.
  • Self-registration is not enabled for the community. Go to Manage Communities, click Edit and make sure the Login settings show that self-registration is enabled.

For more details on setting up a community for self-registration, please refer to the Getting Started with Communities guide.

Wednesday, July 9, 2014

XML Parsing Error: XML or text declaration not at start of entity

I'm not sure whether it's an XML specification requirement, but it appears that when rendering XML with Salesforce there cannot be any whitespace between the apex:page start tag and the first character.

The following code will work:


But the following code with visually pleasing indention will not:


If there are any unexpected spaces present after the apex:page start tag, you will likely encounter an error: XML Parsing Error: XML or text declaration not at start of entity


Monday, June 23, 2014

コンポーネントからページコントローラメソッドを呼ぶこと

初めて日本語でブログ投稿ですから、いろいろな文法的と文化的のミスしてしまって申し訳ありません。下記のコンテンツは「Controller Component Communication」の翻案です。

ある時にapex:Componentからページコントローラメソッドを呼ぶ必要が出て来ます。この場合で、ページコントローラをapex:attributeでコンポーネントコントローラに渡せば、以上の呼ぶことが出来てなります。

標準コントローラお使ってサンプルコードが提供されてお参照してください。サンプルコードはLeadCustomSaveページの作成方法です。


LeadCustomSave.page



ControllerHandleExtension.cls



CustomSave.component



CustomSaveController.cls


Monday, January 27, 2014

Extending Chatter Profile with Custom Subtabs

Out of the box, Salesforce only gives users limited access to user information through the Chatter Profile page. There are two tabs: Feed, showing the Chatter feed, and Overview, giving a nice overview of additional Chatter relationships and the ability to edit ~1 dozen User fields. However, organizations that want to extend the Chatter Profile page will not find any button-click admin options in Setup.

Thankfully, custom Profile subtabs give those orgs an option to extend the Chatter Profile without having to completely re-engineer the entire page (which is not really feasible considering the Chatter feed and related components). What's required is some Visualforce magic to expose related information directly on the Chatter Profile page as subsequent tabs coming after "Feed" and "Overview".


To provide access to personal data without exposing that data to other users, Salesforce provides a thoughtful separation of different subtab use cases. Admins have the option of showing custom subtabs in one or more of four different contexts.
  • Profile (Others): When a user looks at someone else's profile in the internal Salesforce "community"
  • Profile (Self): When a user looks at his/her own profile in the internal Salesforce "community"
  • Profile in Communities (Others): When a user looks at someone else's profile in a customer or partner community
  • Profile in Communities (Self): When a user looks at his/her own profile in a customer or partner community

Without restrictions on what to extend, subtabs really give developers the ability to deliver any functionality desired within the constraints of Visualforce. And knowing that the profile user's Salesforce ID can be retrieved from the sfdc.userId URL parameter, developers can provide a fully personalized experience for the user.

Tuesday, December 3, 2013

Deploying Destructive Changes Using Workbench

Sometimes, especially in the case of custom Apex or Visualforce, a Salesforce admin or developer needs to delete components from an org. However, Salesforce's user-friendly change sets feature does not allow admins to propagate component deletions. The only semi-automated alternative to performing these deletions, especially in production orgs, is to leverage the metadata API.

Fortunately, with the availability of Workbench on Developer Force, the steps required for deploying destructive changes (that delete components) are pretty simple:

  1. Create a package.xml file
  2. Create a destructiveChanges.xml file
  3. Bundle the two files together in a .zip file
  4. Deploy the .zip package using Workbench

As you can see from this sample .zip package, the files are fairly simple and straightforward. Multiple types of metadata can be removed with a single package.

The exact steps for deploying using Workbench 29.0.1 are:
  1. Open the migration menu, then click Deploy
  2. Click Browse... and select the .zip package file
  3. Mark the "Rollback On Error" checkbox
  4. Mark the "Single Package" checkbox
  5. Mark the "Run All Tests" checkbox
  6. Click Next
  7. Review the deployment options, then click Deploy

The results, successful or otherwise, will be displayed in Workbench for you to review once the deployment process is complete.