2

Here's a fairly simple example illustrating the problem that uses only standard objects:

.pages/MyPage.page

A page with an input text box and a button.

<apex:page controller="Remote_MyPage" >

<input id="account-id" />

<button id="button">go</button>

<span
 id="script-params"
 data-remote-action="{!$RemoteAction.Remote_MyPage.query}"
/>

<script src="{!$Resource.MyPageScript}" ></script>

</apex:page>

./staticresources/MyPageScript.resource

A js script that takes the value from the input text box and sends it as the AccountId of a contact to a vf remoting method.

var button = document.getElementById('button')
  , accountId = document.getElementById('account-id')
  , remoteAction = document.getElementById('script-params').dataset.remoteAction

var buildContact = function(){
    var c = {}
    c.AccountId = accountId.value
    return c;
}

var buttonClickHandler = function(){
    var c = buildContact()
    console.log( c )
    Visualforce.remoting.Manager.invokeAction(
        remoteAction
    ,   c
    ,   function(){ console.log(arguments) }
    )
}

button.addEventListener('click',buttonClickHandler);

./classes/Remote_MyPage.cls

A class with a remote action method that takes the contact object and returns a list of contacts from the same account.

public class Remote_MyPage
{

    @RemoteAction
    public static list<Contact> query( Contact c ){
        String QueryString = 
            'SELECT Id, LastName FROM Contact '
        +   ( ( c.AccountId != NULL )
              ? ' WHERE AccountId = \'' + c.AccountId + '\' '
              : '' )
        ;

        return (list<Contact>) Database.query( QueryString );
    }

}

The problem is with the behavior when the AccountId is the empty string. In that situation, I want to get contacts from any Account, and not just contacts who are not associated with an account.

I've tried adding an empty string check after the null check in line 8 of the controller

        +   ( ( c.AccountId != NULL && c.AccountId != '' )

However, the code above causes an Apex run-time exception:

Visualforce Remoting Exception: Invalid id:

enter image description here

What is typically your approach for handling this situation?

7
  • I'm surprised the empty string check doesn't fix it. Worth looking at the server-side logs too. By the way, an unrestricted query of Contacts is likely to run you into governor limits in typical orgs that have hundreds of thousands of Contacts. Suppose the other place the problem could come from is c.AccountId = accountId.value; perhaps check there and set null for an empty string.
    – Keith C
    Commented Mar 26, 2018 at 8:49
  • @KeithC I was surprised too. As for the query, in my actual code, it will use filter criterion from multiple fields on the object being sent over, and there's also a limit on the records returned so that shouldn't be a problem.
    – martin
    Commented Mar 26, 2018 at 8:51
  • @KeithC It looks like using a value of null instead of an empty string will work, but it does add an unfortunate extra bit of complexity to the code. That might be the best we can do here though..
    – martin
    Commented Mar 26, 2018 at 8:57
  • Do you mean in the JavaScript? Good to know if that's the case.
    – Keith C
    Commented Mar 26, 2018 at 9:07
  • @KeithC Yes,it looks like setting the value to null instead of the empty string in the javascript should work.
    – martin
    Commented Mar 26, 2018 at 9:14

1 Answer 1

1

Don't use "empty string" as an Id. Id can ever only be a null value, a 15-character string, or an 18-character string.

In your JavaScript:

c.AccountId = accountId.value || null;

This will convert an empty string to a null value.

In your Apex Code, do not compare an Id to an empty string.

2
  • It looks like null string ids generally behave as I would expect them to. With an object with an empty string id, Contact c = (Contact) JSON.deserialize( '{"LastName" : "Test" , "AccountId" : ""}' , Contact.class );, the empty string value can be detected after casting the Id to a string: System.debug( (String) c.AccountId == '' );, and the id is treated as null during DML insert c;. I think one of the more problematic issues is the c.AccountId.getSObjectType() method, which throws an exception when called on an empty string.
    – martin
    Commented Mar 26, 2018 at 14:43
  • @martin That looks like a bug. Let me say it again. An Id is never an empty string. The correct JSON should be: Contact c = (Contact) JSON.deserialize( '{"LastName" : "Test" , "AccountId" : null}' , Contact.class ); (note the lack of quotes on null). And yes, you should always check if an Id may be null before trying to call methods on it.
    – sfdcfox
    Commented Mar 26, 2018 at 14:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .