Retrieving Parent Visualforce Remote Objects

Salesforce No SoftwareWhy Visualforce Remote Objects?
Salesforce recently rolled out Visualforce Remote Objects as a way to allow CRUD operations to Salesforce objects in a Visualforce Page without having to write code in a server-side controller.  While I don’t have a problem writing code in a controller to handle CRUD actions on an object, if I could skip that step, then why wouldn’t I?

Shallow Vals
Unfortunately, accessing parent objects, lookup, or child objects from a VisualForce Remote Object isn’t currently supported.  Back to SOQL in the controller?  That’s definitely an option, but with a little Javascript magic, we’ve got a good alternative.  Keep in mind that the only technology used for data access in the code below is Visualforce Remote Objects.  Pretty sweet.

Visualforce Remote Objects Setup

<apex:remoteObjects >
    <apex:remoteObjectModel name="Contact" jsShorthand="ContactRemoteObject" fields="Name,Id,AccountId">
    </apex:remoteObjectModel>
    <apex:remoteObjectModel name="Account" jsShorthand="AccountRemoteObject" fields="Name,Id">
    </apex:remoteObjectModel>
</apex:remoteObjects>

We need to set up remote models for getting both the main objects and the parent objects. In my case, I’m using the standard Salesforce objects Contact as the main object and Account as the parent object. I’ve assigned the fields attribute with the list of fields that I’ll be using on this page. As a little something special, my jsShorthand names are actually longer than the original object names. Don’t judge.

Page Layout

<h1>Visualforce Remote Objects Parent Example</h1>

<br /><br /><br />
<b>Name Starts With:</b> <input type="text" id="txtNameStartsWith" />

<br /><br />
<input type="button" onclick="loadContacts();" value="Load Contacts" />

<br /><br/>
<b>Contact List</b>

<ul id="contactList">
</ul>

Nothing fancy here. Functionally, I’ve got a filter textbox, a button, and an empty list that will hold my results. Obviously in a real implementation, you’d take the time to design a visually impressive page. Alright, let’s move on to the fun stuff.

Retrieve Primary Objects

<script type="text/javascript">

    var retrievedContacts;

    function loadContacts() {
        var objContactRemoteObject = new SObjectModel.ContactRemoteObject();
        objContactRemoteObject.retrieve({
            where: { Name: { like: document.getElementById('txtNameStartsWith').value + '%'} },
            limit: 100
        }, function(err, records) {
            processContactRecordsResult(err, records);
        })
    }
    
    function processContactRecordsResult(err, records) {
        if(err) {
            alert(err.message);
        }
        else {
            retrievedContacts = records;
            loadAccountsForRetrievedContacts();
        }
    }

</script>

This Javascript to get the primary objects should look almost identical to how you’d get any results using Visualforce Remote Objects. The biggest difference here is that when I get my Contacts back from Salesforce, I’m calling loadAccountsForRetrievedContacts() which will retrieve the parent Accounts. One other quick note, I’m caching Contacts in a Javascript var retrievedContacts. I’m usually a fan of fewer global variables, so if you accuse me of breaking my own rules, you’re probably right.

Retrieve Parent Objects

<script type="text/javascript">

    var retrievedContactAccounts;

    function loadAccountsForRetrievedContacts() {
        var objAccountRemoteObject = new SObjectModel.AccountRemoteObject();
        objAccountRemoteObject.retrieve({
            where: { Id: { in: getAccountIdListForRetrievedUsers() } },
            limit: 100
        }, function(err, records) {
            processAccountRecordsResult(err, records);
        })
    }
    
    function getAccountIdListForRetrievedUsers() {
        var accountIdList = [];
        
        retrievedContacts.forEach(function(contactRecord) {
            if (! arrayContainsValue(accountIdList, contactRecord.get("AccountId")))
            {
                accountIdList.push(contactRecord.get("AccountId"));
            }
        });
        
        return accountIdList;
    }
    
    function arrayContainsValue(arr, val) {
        for (var currArrayIndex = 0; currArrayIndex < arr.length; currArrayIndex ++) {
            if (arr[currArrayIndex] === val) {
                return true;
            }
        }
        return false;
    }

    function processAccountRecordsResult(err, records) {
        if(err) {
            alert(err.message);
        }
        else {
            retrievedContactAccounts = records;
            displayContacts();
        }
    }

</script>

This is the money code (never heard anybody use that phrase, but it could completely catch on). In loadAccountsForRetrievedContacts() , I’m getting all the parent Accounts for the Contacts we just retrieved. Essentially, I’m just building a list of all the Contact’s AccountId values. The part that took me the longest to get this working was figuring out that the In operator doesn’t like duplicate values in the list, so I’m filtering out any duplicate AccountId values. When the parent Accounts are returned, we hand control over to displayContacts() , which now has access to both the cached Contacts and Accounts.

Display Results

<script type="text/javascript">

    function displayContacts() {
        var contactListUl = document.getElementById("contactList");
        // clear previously loaded contacts
        while( contactListUl.firstChild ){
            contactListUl.removeChild( contactListUl.firstChild );
        }
        retrievedContacts.forEach(function(contactRecord) {
            var parentAccountRecord = getRetrievedAccountRecordById(contactRecord.get("AccountId"));

            var contactString = contactRecord.get("Name");
            contactString += " - Account:  ";
            contactString += parentAccountRecord.get("Name");

            var contactItemLi = document.createElement("li");
            contactItemLi.appendChild( document.createTextNode(contactString) );
            contactListUl.appendChild( contactItemLi );
        });
    }

    function getRetrievedAccountRecordById(accountId) {
        var foundAccountRecord;
        
        retrievedContactAccounts.forEach(function(accountRecord) {
            if (accountRecord.get("Id") == accountId)
            {
                foundAccountRecord = accountRecord;
                return;
            }
        });
        
        return foundAccountRecord;      
    }

</script>

If you’ve used Remote Objects in the past, this should look familiar. There are really only a couple lines different than normal. In the foreach Contact loop, the first thing we’re doing is to get the parent Account for the Contact using getRetrievedAccountRecordById() . In case you skipped over the name of the function, its only purpose is to find the Account using the Contact’s AccountId value. At this point, we have both the Contact record and the parent Account record available to do whatever we want to with them. Out of all the amazing things I could do with this, I chose to get the Account name. Boom!

Not That Hard
After reading through, you’re probably feeling kind of ripped off because I didn’t really do anything you couldn’t have already done on your own. True, but when I was searching for answers on how to get parent Visualforce Remote Objects, this would have at least given me a head start. From what I’ve seen, Salesforce is planning to make further improvements across their Remote Objects technology, so it wouldn’t surprise me if the approach I’ve taken is completely outdated in a couple releases. Good luck, and if you have any lessons learned as you’re using this technique, please post a comment so we can all benefit.

Download Visualforce Remote Object Parent Source Code

Leave a Reply

Your email address will not be published. Required fields are marked *