+ Start a Discussion
BillHansonBillHanson 

Trouble with fieldsToNull

My record update code is working fine with one exception.  If I try to extend the Array class in my Javascript library in any way, then the call to update fails whenever I use fieldsToNull.  The problem seems to be that the update code tries to read the new method as one of the fields to null.  Strange.  I have an extensive js library with many classes extended this way (including several sfdc classes) and have never had this problem before.

Here is the code that I use to set a field value...

      if(value == null){
         if(!this.nillable) throw this.label + " is a required field.";
         if(typeof(record.fieldsToNull) == "undefined") record.fieldsToNull = new Array();
         record.fieldsToNull.push(this.name);
         record.set(this.name, null);
      }else{
         record.set(this.name, value);
      };

... here is an example of an arbitrary method added to the Array class...

Array.prototype.ok = function(){
   alert("OK");
};

... and here is the error message I receive as a result of calling update...

INVALID_FIELD: No such column 'function(){
   alert("OK");
}' on entity 'opportunityLineItem'.

If I remove the Array.prototype.ok function from my library, everything works fine.
I'd really hate to loose the ability to extend my own library.

Any ideas?
Ron HessRon Hess
I have also encountered this, my solution was to re-define a few bits of the connection.js library.  This code has not been tested by our QA team, but it appears to work with my limited testing.

You must include this after connection.js

Code:
/*
 * custom version to avoid serializing functions
 */ 
sforce.internal.Parameter = function (n, v, a) {
 if(typeof(v)==="object" ) {  
  if (v.name) n = v.name;
  if (v.value) v = v.value;
 } 
 this.name = n;
 this.value = v;
 this.isArray = a;
};
/* 
 *  I need to override so that we will not seralize functions, 
 * otherwise this is same as production
 */
sforce.Connection.prototype.writeOne = function (writer, name, value, sobjectNs) {

   if (typeof(value) === 'function') { return ; } 
    if (value === null) {
        writer.writeNameValueNode(name, null);
    } else if (value.toXml) {
        value.toXml(sobjectNs, name, writer);
    } else {
        writer.writeNameValueNode(name, value);
    }
};

 

BillHansonBillHanson
Thanks, I was in the process of stepping through the update code and had just come accross the Parameter method.  This looks like it will work.  I'll test it out this afternoon.
cheenathcheenath
In Ajax Toolkit you do not have to set the fieldsToNull to make a filed null.
You can just set the value to null. For eg:

  record.myField = null;



BillHansonBillHanson
That is true for most field types, but not double.  If you try to set a double to null, you get an error.


BillHansonBillHanson
I have been proven wrong!

Thanks, cheenath, for pointing out the obvious.  :)

For the terminally curious:

I was trying to set a currency field to an empty string rather than null (thought I was already handling this case, but cheenath's comment forced me to look back at the form validation part of my script).

When I got the error message, I started looking for answers because I thought I already was passing null.  That's when I read about fieldsToNull.  When I used fieldsToNull, all worked well until I added a method to the Array class.  If you set a field value to an array that has been extended using the prototype method, the xml serializer serializes the new method along with the array elements.  As Ron Hess pointed out, this is the cause of the problem.

I'm going through all this detail, because I found a workaround that differed slightly from Ron's.  The correct way is to not use fieldsToNull at all.  But if we ever need to set field values using an array, this might come in handy....

Code:
/**
* Override!
* This method has been overridden to prevent serialization of array methods.
*/
sforce.XmlWriter.prototype.writeNameValueNode = function(name, value) {
    if (value === null) {
        this.writeStartElement(name);
        this.writeNamespace("http://www.w3.org/2001/XMLSchema-instance", "xsi");
        this.writeAttribute("xsi:nill", "true");
        this.writeEndElement(name);
        return;
    }

    if (value.toUTCString) {
        value = sforce.internal.dateTimeToString(value);
    }
    if (typeof value == "boolean") {
        // boolean 'false' values get joined in string buffer,
        // so convert to strings:
        value = value — "true" : "false";
    }

    if (value && value.join) {
        for (var v in value) {
            if (typeof(value[v]) != "function"){ // prevents serialization of methods.
                this.writeStartElement(name);
                this.writeText(value[v]);
                this.writeEndElement(name);
            }
        }
    } else {
        this.writeStartElement(name);
        this.writeText(value);
        this.writeEndElement(name);
    }
};