Guest Post: Matt Lacey is a Co-Founder of S. P. Keasey Trading Co and Proximity Insight. Salesforce and Force.com MVP. Proposer and moderator of Salesforce StackExchange. Co-host of Code Coverage. Blogger at laceysnr.com Fan of many things including games development, snowboarding and Atari computers.
In this post we’re going to create a mobile-oriented Visualforce page that leverages custom CSS and KnockoutJS to build an easy-to-use contact editor that facilitates easy and quick editing of all contacts on an account. It is especially suited to mobile environments since it uses remoting rather than standard Visualforce actions to read and write data.
Step 1: Create a Visualforce Page That Uses the Account Standard Controller
Create a new Visualforce page and give it a sensible name, such as ‘Rolodex’, and replace the initial code with the following. As you can see we’re hiding the standard UI, declaring that we don’t want the standard CSS, and specifying that we want to use the Account standard controller.
Make the page easy to access by creating a new custom button and putting it on the Account layout. If you’re comfortable with this process, add it and move on to Step 2. If you’re not sure how to add a custom button, then navigate to Setup -> Customize -> Accounts -> Buttons, Links, and Actions and click New Button or Link. Fill in the button details as shown below and click Save. Your Visualforce page will be available because we used the Account standard controller.
Finally, navigate to the Accounts tab and choose an Account. Then click Edit Layout to open the page layout editor, drag the new custom button into the custom buttons area, and click Save.
If you click the button you’ll now see your exciting new page that shows the Account ID. Time to make it a bit more interesting!
Step 2: Getting Started With KnockoutJS
The next task is to sort out the View part of the equation, the part that displays the data provided by the View Model. The View in this tutorial is essentially all of the markup in the page, so replace the old line with the <h1> tags with the following code.
As you can probably guess, KnockoutJS uses a special attribute called data-bind to bind parts of the View to the data in the View Model. KnockoutJS provides different types of binding to deal with various use cases, such as input, output, looping, etc. In this case, we’re using the text binding to use the accountName property of the View Model as the content for the <h1> tags.
If you’ve viewed the page at this point, you won’t have seen anything on the screen, and that’s because we haven’t connected to the View Model to it’s View. We do this with a call to the applyBindings() method provided by KnockoutJS. This method takes one parameter, which is an instance of the View Model. We want this link to be created when the page has loaded, so we’ll create a quick one-line function and assign it to window.onload right before the closing script tag.
No rocket science here, and while you might want to consider using Bootstrap or something similar to get easy, mobile friendly, styling, I wanted to keep the source of this tutorial page as free from clutter as possible.
Step 3: Building On The Basics
Before making further changes to the page, we’ll first create the Apex class that will provide data from our model. In the Salesforce Developer Console choose File -> New -> Apex Class and then specify a name, e.g. ‘RolodexRemoting’. Replace the default class content with this code, which is a relatively standard starting point for an extension controller, with the small exception that the class has global scope, which is required for remoting classes. The constructor doesn’t have anything in it’s body as we’re not going to use it, we merely need this constructor so that Visualforce will let us use the class as an extension controller alongside the Account standard controller the page uses at present.
Next, we need a remoting method that returns the contacts and fields we’re interested in. For this exercise this is a one-liner, and simply returns the result of a SOQL query as a list of Contact records. It is static (as all remoting methods must be), and pulls the ID of the account being used from the page parameters.
Once the class has been saved, switch back to the page source and add our new Apex class as an extension controller using the extensions attribute in the opening page tag:
Now we need to modify the View Model so that it pulls a list of contacts from the controller, but to do that we’ll need somewhere to store them within it. Obviously an array is required since we’re dealing with a list, but because this will be something that changes over time (using remoting means we’ll load the contacts after the page has loaded) we need to use what’s known in the land of KnockoutJS as an observable array. Observables and observable arrays are mechanisms provided KnockoutJS that create dynamic, two-way bindings between the View and View Model. This means if a value changes in the View Model it will be reflected in the View, and vice versa. Modify the View Model so that it looks like this:
The upshot of this is that because we our Apex method returns a list of contacts, we can simply assign the result straight to our contacts observable array! Before the closing brace of the View Model, add the code snippet below. This calls the method provided by the extension controller (LoadContacts), which uses a callback function as the second parameter. If you’ve not used them before, callback functions are functions that are run by the Visualforce remoting framework when the request to the server has completed. The resulting parameter will be an array of contact records, and we use this data without modification.
For our last trick in this step, we’ll make sure these contacts we’re loading are displayed on the screen as a list under the account name. To loop over the contacts we need to use another Knockout binding type. This time we’re going to use the foreach binding. This can be applied to any element (in this case a div) and then the contents of that element, including bindings, are repeated and evaluated for each item in the array (very similar to the the Visualforce element <apex:repeat>).
Add the following code after the <h1> tags and reload the page, you should see the account name as before, and then after a short delay the list of contacts will appear when the remoting call completes.
In this code, the Name bound to the text for the <h2> element is the name of the field to display from the contact. For the phone number and email fields, we’re using a slightly different syntax. Inside of a foreach loop, $data allows you to refer to the actual array entry itself (i.e. the contact), and referencing the fields this way will prevent an error if either of those fields are blank for a contact in the list, showing ‘undefined’ instead.
At this point, your complete Visualforce page code should look like this:
Step 4: Taking Action
Now that the list of contacts is being displayed, we’ll look at leveraging some more KnockoutJS bindings to make things a bit more interactive. We’ll add a new panel that is displayed instead of the list when a contact is clicked, allowing their details to be edited easily. Hopefully this is where the power of KnockoutJS and it’s simplicity will become readily apparent. We’ll need a property to reference the currently selected contact, and as we’ll want the UI to respond when a contact is selected, that property will be an observable, so add this to the View Model:
To provide a selection mechanism, we need to create an action on the View Model that can be called from the View. So after the remoting call we’ll create a new function assigned to a property on the View Model. This is short and sweet. It simply takes a contact as a parameter, and assigns it to the selected property that we just created:
Selecting a contact is one thing, but since we’re going to switch the UI when a contact is selected, we’d better make sure we have a way to clear that selection also:
Now that we’ve made some the changes to the View Model, we’ll modify the View to add a panel that will show the selected contact’s details for editing. This goes after the main div, and includes no less than three new binding types: it uses visible so that it is only displayed when selected has a “non-falsey” value, with binding to specify what part of the View Model this part of the View should use, and the value of the binding to tie properties to input field values.
In this markup, Name, Phone, and Email are not properties of the overall View Model, but of a specific contact, which is why we use the binding to indicate that the contents of this div should use the selected contact property as its data source. As before, $data is used so that blank values don’t cause any problems.
We’ve got a method to select a contact, and a way of displaying that contact, but no way of calling the method as of yet. For this we can simply use the click binding to call the selectContact function, and by default it will pass the current item when used in a foreach. $root is required because we’re working with repeated elements, and in the repeated content our main binding is to a contact, not the overall View Model (hence why one Name binding in the source works for each contact record).
Refresh your page and click a contact. When you do the list should disappear and the new editing panel should be displayed, pre-filled where values exist. Unfortunately, we’re now stuck on this view so a couple of buttons wouldn’t go amiss. Since we’ve already got a function to clear the selected contact, it should come as no surprise that adding a Cancel button is trivial, so add the following button, reload the page, and now you should be able to go forward and back between the list of contacts and the editing panel.
Our page would be a lot more useful if the user could actually save their changes. First, we’ll add a new method to our Apex remoting class to save a record (using the ever handy upsert):
And then we’ll add a Save button to the edit panel:
Last but not least, we need to make sure the list of contacts is upated with the new details that we just stored, and while we’re at it, we might as well refresh the list from the database in case anybody else has been busy in the mean time. To do this we can simply change our old direct remoting call to be named function in the View Model:
… and then we can simply call that function from the saveContact function, so that complete it looks like this:
Now once you reload the page you should be able to edit all of the contacts on an Account quickly and easily!
This has been a head-long charge into the world of using KnockoutJS on the Salesforce1 Platform and there’s much more that could be said with regards to mobile styling, supporting more dynamic pages (field sets work well with Knockout!) and more, but hopefully it’s piqued your interest and given you the impetus to explore this great framework further. To learn more about using KnockoutJS there really is no greater resource than it’s own documentation which is written in a concise, organized, and easy-to-consume manner. In addition there is a great tutorial on building a more involved single page app, which is also well worth checking out.