Category Archives: Uncategorized

DataTables in Visualforce, part 2

In the last post, I showed how easy it is to turn a plain html table into a functional DataTable. In this post, I’ll show how you can build on that and and make the table even more dynamic. In this example, we’ll build a datatable that lists accounts that allows you to expand an account to see a list of contacts for the account.

First, instead of using a controller to return data for the table and build it using an <apex:repeat>, I am using Javascript Remote Objects to get 100 accounts. Note that the limit is 100 records at a time, so if you have lots of accounts, you may need to implement filtering or pagination (maybe a topic for a future post). The biggest benefit of Remote Objects  is that we don’t need a controller. We use the “ajax” option to specify the data for the table. The biggest issue I ran into with this was that it expects an object with a “data” property. You can’t just return the records from the remote object call.

In the columns option for the datatable, I have to specify where to pull each column from. This is done with { “data”: “_props.Phone”,
“defaultContent”: ” }. The defaultContent option tells the datatable to replace any undefined properties with a blank, preventing errors from being thrown.

Next, we have to handle the clicks to expand the row and display contacts. This code is fairly straightforward with another remote object query to get the list of contacts for the account. I then just build up a html table to append in the child section.

Here’s a screen shot of what it looks like when we are all done.

datatables ajax

And here is the entire page.

Visualforce Dispatcher Revisited

Funny how things can work just fine for the longest time and then you get a head scratcher. I just ran across an issue with my Visualforce dispatcher class which allows you to control which page to take a user to based on the record type being created.

The problem was that a user had selected in the settings to bypass the record type selection page and always use their default. Turns out when a user does that, the record type Id isn’t passed to your dispatcher page as a parameter. A Google search turned up this Stack Exchange question and I was able to solve the issue by looping through the record types and inspecting them to see if they are the default for that user. If it is, then we use it to determine which page to send the user to. I’ve updated the original Gist so you can use the code.

URL Hacking Cross Filter Reports

Warning: The Following Post is a Completely Unsupported Hack. Salesforce may make changes at any time that makes this not work.

You probably know how to pass report parameters using the url. This is helpful when you want to create links from a record in Salesforce to a related report. Cross filter reports can also be passed parameters, but it is a little more difficult to do than with a standard filter.

The first thing I did is create a report that uses a cross filter. In this example, we’ll look for accounts that have an opportunity with a close date after a certain date.

cross filter report

I then looked at the page source and found the relevant hidden fields we need to work with.

cross filter source

As you can see there are a lot of fields that need to be provided. Unfortunately you can’t set up the cross filter and just pass in the values like you can with standard filters. You need to pass in all filters and save the report without a cross filter.

Let’s examine each one to try and figure out what they mean.

ptable0 – This parameter corresponds to the main object in your report. I haven’t quite figured out what goes here, but it seems to be CUST_ID for custom objects and [OBJECT NAME]_ID for standard objects.

ocond0 – Use w for with and wo for without

rtable0 – This is the cross filtered object. It should be the object name for standard objects and the object ID for custom ones.

rtablecol0 – This is the column on the cross filtered object that corresponds to the parent object.  For standard objects, use the field name and and for custom objects, use the field ID.

sfpc0_0 – This is the field to filter on. For standard objects, use the field name and and for custom objects, use the field ID.

sfpn0_0 – This is the filter operator. It can be values such as eq, ne, gt, lt, ge, le.

sfpv0_0 – This is the value you want to filter on.

cross filter report and fields

 

Now that we have a better idea of what each one does, we can use them in a URL. So in this example, our URL will look like this

/[ReportID]?ptable0=ACCOUNT_ID&ocond0=w&rtable0=Opportunity&rtablecol0=Account&sfpc0_0=CloseDate&sfpn0_0=ge&sfpv0_0=1/1/2014

We can just change the date at the end to get it to populate a different date. Just save your report without any cross filters and then use the URL parameters to filter accordingly.

I’ve found that the best way to figure out all the parameters is to first create a report with the filter, run it and then view the page source. Just search for the list of hidden fields and look for the values that you should pass.

Good luck with your URL hacking!

Using Developer Console to Troubleshoot Code

Confessional time: my org is a mess. There have been way too many developers in it and over time it has become a giant pile of triggers and code. It can be a bit intimidating to clean up, but the developer console can help. In this post I’ll show how I use some of the features of the dev console to find where my code can be improved.

One of my tests recently stopped working due to the dreaded “Too many SOQL queries” error. I was able to find the offending SOQL statements with the help of the developer console.

First, open up the console so logging will be captured. In Salesforce, perform that action to replicate the problem or execute the code you want to look at. You should see the log appear in the Logs list. Open the log and switch perspective to Analysis (Debug > Switch Perspective > Analysis(Predefined). This perspective gives you tons of information.

I’m interested in the Executed Units tab under Execution Overview. Since I know I have a problem with my queries, I click on all the buttons except for Queries to make only Queries visible. This gives us a list of all the queries executed. Immediately, I can see a few queries that were executed 16 times! Uh oh. Looks like I have some code that can be optimized. With my new knowledge, I can work towards making my code bulk friendly.

analysis perspective

 

Take some time to poke around in the perspectives. It really gives you insight into how your code is executing. Happy spelunking!

Yet Another Test Factory

When writing unit tests, it is best practice to centralize the creation of all your test data. While there are a lot of examples of ways to do that on the web (SmartFactory ), I’ve never been completely satisfied with them. SmartFactory is great if you want to be sure you have data in all your fields, but since I know my org and what the data should look like, I prefer to specify field values. Some of the problems I wanted to solve:

  • Minimize number of code statements executed (SmartFactory makes debug logs huge).
  • Have different object templates for various scenarios.
  • Be able to override values for specific one-offs tests.

You can find the code on Github in my Salesforce-Smart-Factory repository. Here’s how you can use it.

// To create an object, just pass an instance of the new object to the method.
// The TestFactory will pre-fill all the fields we typically need
Account a = (Account)TestFactory.createSObject(new Account());
insert a;
 
// You can also set values to be used. Any values set in the constructor will override the defaults
Opportunity o = (Opportunity)TestFactory.createSObject(new Opportunity(AccountId = a.Id));
 
// You can also specify a specific set of overrides for different scenarios
Account a = (Account)TestFactory.createSObject(new Account(), 'TestFactory.AccountDefaults');
 
// Finally, get a bunch of records for testing bulk
Account[] aList = (Account[])TestFactory.createSObjectList(new Account(), 200);

Team Development on Force.com

One of the challenges of working with a team of developers is managing the changes everyone is making and not have one developer overwrite the changes another one makes. In this post, I’ll describe the setup I’ve found to work. I’ll be writing followup posts with more detail describing exactly how I use some of these tools. All tools described work on both Windows and Mac.

1. One developer per sandbox

Each developer should get their own sandbox or developer edition to work in. All changes should be made in their sandbox. This prevents a developer from making a change to a class in their IDE which hasn’t been refreshed recently overwriting a change another developer did recently.

2. Sublime Text with Mavensmate

The combination of Sublime Text with the MavensMate plugin is really powerful. MavensMate makes it easy to retrieve metadata from Salesforce and saving is super quick compared to the Eclipse IDE. I never want to open Eclipse again.

3. Use Source Control to Track Changes

I prefer to use Git because that’s what all the cool kids seem to be using and the tools out there are fantastic. I use Bitbucket because they provide free private repositories for up to 5 developers. The nice thing is there are many options out there that are free/low cost and you don’t have to install a server locally. I like to use the free SourceTree client because I can never remember the git commands. It also lets me more easily see the changes I’m about to commit. As each developer works, they should be working on their own branch and then merging their changes into the master branch as they are finished.  I can’t tell you how many times I’ve used source control to go back and see the changes done. In one situation, a change caused major issues, I was able to go back, reverse the commit, and we were back in business really quickly. When a developer needs to bring their sandbox back in sync with the master branch, they can use the Force.com Migration Tool to deploy all the changes back into the org.

4. Use a CI Tool to Build to a Staging Sandbox

Now that you’ve got everything merged into source control, you need an org to test everything in. You could have each developer deploy their changes manually to a staging org, but I prefer to use a Continuous Integration tool to do it for me. I recently found Drone.io and it is really easy to setup to automate the deploy of all metadata to your staging org.  Drone.io adds hooks to Bitbucket so when a change is committed to the repository, it automatically begins a build using the Force.com migration tool. You can get emails on successes and failures. The one drawback is that there isn’t a way to deploy destructive changes automatically. Any deletion of objects, classes, pages, etc need to be done by hand.

I hope this description of my environment helps you get your team up and working peacefully together!

 

 

Using Regex to Parse Text Fields

Regular Expressions always seems very complicated, but they can elegantly solve some complicated problems. I had an interesting problem where I needed to find some text that matched a pattern in a text field and pull it out. I ended up turning to using a regex matcher to find the information I needed.

The hardest part of regex is coming up with the correct pattern. One site that can help with this is www.txt2re.com. This site lets you enter sample text and it gives you regular expressions matching certain parts of it.

In this example, I’m looking for a date that is prefixed by the text “Completion Date:”. My date will always be in the MM/DD/YYYY format, so my pattern is pretty simple. I declare a pattern and a matcher and then loop through all the matches and output them to the debug log.

String DATE_PATTERN = 'Completion Date:(\\d{1,2}/\\d{1,2}/\\d{4})';
Pattern p = Pattern.compile(DATE_PATTERN);
Matcher pm = p.matcher('Some text, more text. Completion Date:11/15/2012 even more' +
                         'text Completion Date:5/6/2012');
while (pm.find()) {
	System.debug(pm.group(1));
}

While this is a pretty simple example, it shows how you can avoid doing searches, finding indexes and performing substring operations in text fields.

Change Sets and Profile Permissions

Did you know your change sets may be including more permission changes than you thought? I recently deployed a new field in a change set along with the “profile settings for for included components”. I selected all the profiles in my org because I wanted to make sure all my profiles could see the new field. After deploying, I discovered that the change set deploy had removed one of the login IP ranges for a profile. Turns out that is expected behavior as described in the help.

This behavior was unexpected to me and didn’t seem right, so I started asking around and was able to talk to the PM for Change Sets, Andrew Smith. We had a great talk about change sets and I learned a thing or two that I thought would be nice to share with others.

First, change sets will modify many profile settings when you include them in the “profile settings for for included components” section. Not only will it give appropriate permissions for things such as fields, but it will also overwrite login IP ranges among other things. (Take a look at this help doc for the entire list.) In Winter 14 this list gets expanded and will also include user permissions such as “Manage Users”. I tested this in a couple of Winter ’14 sandboxes and was alarmed to see that the audit trail did not record any of the user permissions changes. The moral of this story is that you need to be sure your profiles in your sandboxes are exactly what you want as the changes will move with the change set.

Second, we discussed that change sets are not typically destructive, but there are certain cases where change sets will remove items:

For instance, we delete picklist values in a field that you migrate.  Same goes for adding/removing workflow actions associated with a rule when you move the rule (the link to the actions – not the actions themselves).  Our general rule is we don’t delete things you can add to a change set directly (think field, object, report), but we will update (including removal) sub aspects of a component as part of migrating that component.

Change sets are a great feature and I’m looking forward to future clarification on what can and can’t get deployed as well as improvements to the UI for selecting items to add to the change set.

Chatter Mobile: More Than Just Chatter

Have you looked at Chatter Mobile recently? Version 4.1 for iOS just hit the app store and it looks great! I really wish Salesforce would rename the app since it now does so much more than just Chatter. I know many people who have not even been interested in the app because they don’t want Chatter, they want their Accounts, Contacts, etc. While Salesforce has made some improvements to the Chatter side of things, the parts I’m most excited are about are the the changes they’ve made to view, edit, and create records.

One big enhancement Salesforce made is access to global search. Search is now in the top of the left navigation bar. You can use the search to quickly find your records and work with them.

Another great way to improve productivity for your mobile users is to give them the ability to create records. Want to create an opportunity or log a visit immediately after visiting a client? You can use the publisher actions introduced in Summer ’13 to do so.

Chatter Publisher Actions   Log a Visit

Want to see how you are doing? Dashboards are also easily accessible in the left nav bar.

There’s more in store with the Winter ’14 release just around the corner. In that release, we will be able to create Compact Layouts to customize the data presented on the mobile device. I’m hopeful we’ll see Visualforce pages allowed in Chatter Mobile soon. When that happens, we will have a great option for our mobile users. Now if they’d only change the name from Chatter to something more universal…

Getting the Most From the #Salesforce Community

I’m often asked in comments or through my contact me page how to learn more about Salesforce. My number one recommendation is to get involved in the community. The Salesforce community is one of the most active I’ve ever experienced in all my years in IT. Salesforce users are passionate about the product, and are willing to help others get the most of it. This post shares some of the ways I’ve been involved.

Asking Questions: There are a lot of places you can ask for help. You get the best results when you ask the questions correctly. Here are my tips for writing a question that will get a good answer:

  1. Do your research first. Use the custom Google search at findsf.info to search blogs, help docs and other Salesforce resources. Chances are you’re not the first person to come across the problem.
  2. Show the research you’ve done in the question. For example, you might say, “I found this blog post at www.awesomesalesforcestuff.com, and it is close, but is missing a couple of points.” People are more willing to answer your question if you show you’ve done your homework and aren’t just trying to get someone else to do your work for you.
  3. Include screen shots whenever possible. Screen shots provide context that is hard to convey with words. If you have an error message, include the entire message and the steps you took to duplicate the error.
  4. Write in complete sentences. I can’t tell you how hard it is to read some of the questions out there!

Answering Questions: Once you’ve gained a bit of experience, start answering some of the questions. Again, make sure your answers are high quality. Don’t go for quantity. Select a few ones you are really comfortable with answering and provide a great answer. Your reputation will grow as you continue to provide really good answers. If you don’t know the answer, try to do some research of your own. You can learn a lot by trying to figure things out.

Answers: This is the official community at https://success.salesforce.com/answers. This is one of the best places to get your configuration, formulas, and other “button-click” questions answered.

StackExchange: This Q&A site at http://salesforce.stackexchange.com/ is less than a year old, but has some great answers

Twitter: Perhaps my favorite for quick questions. Use the #askforce hashtag to get in front of a bunch of people ready to answer your questions. Twitter also provides some great interactions with other Salesforce users. Start out by following the Salesforce MVPs. They are a great group if I do say so myself!

There are plenty of other places to participate, but those would be my top three haunts. Hope to see you out there!