5

I'm passing a Javascript object through JS Remoting to update an Account record. However, if I update the NumberOfEmployees field, I'm getting the following INVALID_TYPE_ON_FIELD_IN_RECORD Employees: value not of required type: 1: [NumberOfEmployees]

String-type fields seem to work just fine. Is there something I'm missing about Integers?

The Apex:


@RemoteAction
    public static void putAccount(Account a){
        update a;
    }

The javascript:


function Account(){
    this.Id = null;
}
function putAccount(){
    var acct = new Account();
    acct.Id = document.getElementById("accountPutId").value;
    acct.NumberOfEmployees = parseInt(document.getElementById("accountPutNumEmp").value);
    console.log(acct);
    AccountRemote.putAccount(acct, function(result, event){
        console.log(event);
    });
    document.getElementById("accountPutId").value = "";
    document.getElementById("accountPutName").value = "";
}

The JSON object logged to console just before the Remoting call:


Account {Id: "001o000000BbbzbAAB", NumberOfEmployees: 1} 

Account.Name works with this just fine. Am I missing something obvious?

  • UPDATE: This has been accepted as a bug by R&D. I don't typically follow bugs closely, but if I hear of news of its resolution, I will try to feed this back. – pchittum Nov 6 '14 at 11:39
2

After quite a bit of testing, this does seem like a bug to me. I wasn't able to make this work, and did quite a bit of fiddling with data types, setting input type on the input tag to number, etc.

I found a workaround, using a wrapper class to accept the payload for the remote action call, then copying that into an account object in the Apex code. This requires a bit more effort and code, but it seems to work.

My example is also making use of a second field AnnualRevenue which I was using in comparison to NumberOfEmployees just for testing purposes.

Visualforce Page

<script>
function putAccountWithWrapper(){

    var acct = {};
    acct.RecId = document.getElementById("accountPutId").value;
    acct.Employees = document.getElementById("accountPutNumEmp").value ? document.getElementById("accountPutNumEmp").value : null;
    acct.AnnualRev = document.getElementById("annRev").value ? document.getElementById("annRev").value : null;

    console.log(acct);
    RemoteApexTestNumOfEmployees.putAccountWithWrapper(acct, function(result, event){
        console.log(event);
    });
}
</script>
<div>
    <input id="accountPutId" type="text" placeholder="Id"/>
    <input id="accountPutNumEmp" type="number" placeholder="Num Of Employees"/>
    <input id="annRev" type="number" placeholder="Revenue"/>
    <button onClick="putAccountWithWrapper()">
        Go Using Wrapper
    </button>
</div>

In this one, I copy Id, but the other two fields, I am explicity setting fields to null when no value is present. There are other ways to do this, perhaps, but I'll use this in the controller to make certain I'm not accidentally nulling out values that already exist.

Apex Class

public class RemoteApexTestNumOfEmployees {

    @RemoteAction
    public static void putAccountWithWrapper(Wrapper w){

        Account a = new Account();

        a.Id = w.RecId;
        if (w.Employees != null) a.NumberOfEmployees = w.Employees ;
        if (w.AnnualRev != null)a.AnnualRevenue = w.AnnualRev ;

        update a;

        System.debug('nothing');
    }

    public class Wrapper {
        public Id RecId;
        public Integer Employees; 
        public String Name;
        public Decimal AnnualRev;
    }
}

Here again, I'm looking for nulls and not initializing the fields in the sObject when nulls are passed in so I'm not overwriting existing data.

Using the wrapper, I was finally able to get NumberOfEmployees to save.

  • Yep, totally a bug. I was using the same fix as well, but didn't post, so you get the credit. Thanks for looking into this. Any idea about how to get SFDC to look into this? – ricka Oct 31 '14 at 14:03
  • I have already posted it internally (I work for Salesforce) :-) – pchittum Nov 3 '14 at 13:04
0

I think your problem lies in this:

function Account(){
  this.Id = null;
}
...
var acct = new Account();

This is one of those squidgey Javascript things that I kind of get, but when you invoke an object with the new operator, it does treat it differently, and somewhere deep down in the ECMA Script 5 guts, you're probably doing something that when it arrives in the Remoting API it doesn't agree with it.

I would suggest using the JS object literal notation (I've not had trouble with it anyway) for creating your account object. You don't need the Account() function anyway. It is just extra code at this point. Skip it and just do this:

function putAccount(){
  var acct = {
    "Id" : document.getElementById("accountPutId").value,
    "NumberOfEmployees" : parseInt(document.getElementById("accountPutNumEmp").value)
  };
  console.log(acct);
  AccountRemote.putAccount(acct, function(result, event){
      console.log(event);
  });
  document.getElementById("accountPutId").value = "";
  document.getElementById("accountPutName").value = "";
}
var acct = {};

Alternatively, this might work:

AccountRemote.putAccount(JSON.stringify(acct), function(result, event){
    console.log(event);
});

Regardless, I'm pretty sure the use of the 'new' operator is your problem. I put together a little test on jsbin like this:

function Account(){
  this.Id = null;
}

var acct = new Account();
acct.Id = '011240000003gwe';
acct.NumberOfEmployees = 1; 


var acct1 = {
  "Id" : '011240000003gwe',
  "NumberOfEmployees" : 1
};

console.log(acct == acct1);
//output: false

So clearly how JS looks at these two things is fundamentally different.

  • I tried implementing your solution with JS object literal notation and it did not change anything. Also, the JSON.stringify(acct) doesn't work as the remote function is expecting an Account, not a String. While new may cause some troubles, I do not believe it is the root cause here. Any other thoughts? – ricka Oct 30 '14 at 22:21
  • Interestingly enough, I just tried this with a custom number field I created on account, and both my way and your way work. That means this is definitely something either with standard fields or with Account.NumberOfEmployees specifically. Maybe a bug? – ricka Oct 30 '14 at 22:28
  • I have some time to play with this now as last night was just me shooting from the hip and not testing...let me try your code in my own org and see what comes up. – pchittum Oct 31 '14 at 10:00
0

I ended up writing a quick solution that didn't require a wrapper:

@RemoteAction
public static void putEntity(SObject entity) {
    if (entity.getSobjectType() == Schema.Account.getSObjectType()) {
        Object temp = entity.get('NumberOfEmployees');
        if (temp != null) {
            String numberOfEmployees = (String)entity.get('NumberOfEmployees');
            try {
                entity.put('NumberOfEmployees', Integer.valueOf(numberOfEmployees));
            }
            catch (Exception e) {}
        }
    }

    update entity;
}

By pulling the NumberOfEmployees value out of the SObject and then putting it back in as an Integer Type the issue is resolved.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.