function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
SteveBowerSteveBower 

I'm having trouble with IE. Possible bug with loadSelectElements(). Possible Fix.


I'm posting a lot of code here, and I have comments in the code to explain what to try.  This is a goofy one to me (or perhaps it's just too late and I need sleep).  Either way, if you can take the S-Control below and throw it into a Custom Link somewhere (anywhere, just so you can launch it), I'd appreciate any explanations.

Note that this is IE specific and I'm using IE 6.0.2900...

In a different s-control, IE throws an Object exception error on this line in the loadSelectElement function:

            opt.appendChild(adoc.createTextNode(df));

But, even though the bug is repeatable in the larger s-control, I'm unable to get exactly that error in this smaller sample.  However I get other strange behavior.

I appreciate any feedback, Steve Bower.

Code:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title></title>
<script src="https://www.salesforce.com/services/lib/ajax/beta3.3/sforceclient.js—browser=true"
 type="text/javascript"></script>
 

<script type="text/javascript">
// If I don't have this fix, I get a Secure/Insecure warning box every time I execute the s-control.
 Sforce.Client.prototype.createWait = function() {
 var w = Sforce.doc.getElementById("sfdc_waiter");
 if (w != undefined) {
  return w;
 } else {
  w = Sforce.doc.createElement("iframe");
  w.style.overflow = "visible";
  w.frameBorder = "no";
  //w.style.backgroundColor = "transparent";
  w.allowTransparency = true;
  w.id = "sfdc_waiter";
  w.name = "sfdc_waiter";
  w.src = "javascript:false;";  // This is the added line.
  return w;
 }
};
</script>

<script type="text/javascript">
// Don't know why, but if I include browser=true, the page never stops loading.
// In the sense that the loading icon never stops spinning.  However, turning off
// the busybox does the trick, so it must be related to that, but I'm not going
// to bother figuring out why.
Sforce.Client.prototype.busyboxenabled = false;
</script>


<script type="text/javascript">
Sforce.QueryResult.prototype.SBower_loadSelectElement = function(selectElement, sorted, valueField, displayField, formatString) {
 this.sortf = function(x, y) {
  if (x.text < y.text) {
   return -1;
  } else if (x.text == y.text) {
   return 0 ;
  } else {
   return 1;
  }
 };
 if (selectElement.options == undefined) {
  var sel = Sforce.doc.getElementById(selectElement);
 } else {
  var sel = selectElement;
 }
 sel.options.length = 0;
 if (sel.ownerDocument != undefined) {
  var adoc = sel.ownerDocument;
 } else {
  var adoc = sel.document;
 }
 if (this.size > 0) {
  var options = new Array();
  for (var i=0;i<this.records.length;i++) {
   var vf = this.records[i].get(valueField);
   if (Sforce.Util.dltypeof(displayField).toLowerCase() == "array") {
    var df = formatString;
    for (var j=0;j<displayField.length;j++) {
     var regex = new RegExp(displayField[j], "g");
     if (formatString == undefined) {
// I also think this is goofy and would be better with:
      //df = this.records[i].get(displayField[j]);    // Old
      // Start of New.
      if (j==0) {
       df = this.records[i].get(displayField[j]);
      } else {
       df = df + " " + this.records[i].get(displayField[j]);
      }
      // End of New.
      
     } else {
      df = df.replace(regex, this.records[i].get(displayField[j]));
     }
    }
   } else {
    var df = this.records[i].get(displayField);
   }

/* This is the old code:
   var opt = adoc.createElement("OPTION");
   opt.value = vf;
   //opt.text = df;
   opt.appendChild(adoc.createTextNode(df));
   opt.record = this.records[i];
   options.push(opt);
*/
// Replaced with this line:
   options.push(new Option(df,vf));
  }
  if (sorted && sorted == true) {
   options = options.sort(this.sortf);
  }
  for (key in options) {
/* This is the old code:
   sel.appendChild(options[key]);
*/
// Replaced with this line.
   sel.options[sel.length] = options[key];
  }
  return;
 } else {
  return;
 }
};
</script>


 <script language="javascript">
<!--
function init()
{
 sforceClient.registerInitCallback(doit);
 var ir = sforceClient.init("{!API_Session_ID}", "{!API_Partner_Server_URL_70}", true);

}
function doit() 
{
    var flds = sforceClient.DescribeSObject("contact").fieldList;
 var contacts = sforceClient.Query("select " + flds + " from contact");
 var t1 = document.getElementById("test1");
 var t2 = document.getElementById("test2"); 
 var t3 = document.getElementById("test3");
 var t4 = document.getElementById("test4"); 

 contacts.loadSelectElement(t1,true,"id","lastname");
 //contacts.SBower_loadSelectElement(t1,true,"id","lastname");    // This will fix it.
 t2.options[0] = new Option("-None-","");   // Works if this is removed...
 
 contacts.loadSelectElement(t3,true,"id","lastname");
 //contacts.SBower_loadSelectElement(t3,true,"id","lastname");
 t4.options[0] = new Option("-None-","");
/*

 
Remember, this is only visible in IE.  In Firefox everything works. 
 
 
So, to Test:  

1. Try this in IE and explain to me why #1 is displayed incorrectly but #3 is correct.
The code is the same, the HTML below is different.

The original loadSelectElement code will work if I get rid of the line setting the second 
select box to "-None-".    But, is a totally valid thing to do.  And, you would think that 
it should have no impact on the first Select box.

2. I believe it has something to do with the way the Option elements are generated, or perhaps something
with the "adoc" way of doing things... 
If you use my modified prototype above, SBower_loadSelectElement, it works properly in both cases, but, since
I don't really know what's going wrong, I hesitate to declare this a solid "fix".

Any input–  Thanks, Steve Bower.


Notes:

In the loadSelectElement code there are several other goofy things:

1. I have no idea why the entire QueryResult Records structure is being copied into the Options array
of the Select element.  Perhaps it's to have it available for use later, but that's kind of overkill.
You'll probably still have the QueryResult object that you used to invoke loadSelectElement kicking around,
and you can refer to it's records with the selectedIndex of the element.  It can make for a huge Options collection
for no reason.

2. The logic/code for the FormatString stuff is clever, but the two lines:
 if (formatString == undefined) {
  df = this.records[i].get(displayField[j]);
Should probably be:
 if (formatString == undefined) {
  if (j==0) {
   df = this.records[i].get(displayField[j]);
  } else {
   df = df + " " + this.records[i].get(displayField[j]);
  }

 Meaning, if there is no formatString defined, use concatenation with a space. Otherwise there is no point going through the loop in the first place, even if the displayfield is an array. Some sample doc would also be helpful, otherwise nobody would ever figure out that what is allowed is: contacts.loadSelectElement(element,true,"id",["lastname","firstname","suffix__c"],"firstname lastname suffix__c"); */ } //--> </script> </head> <body onLoad="init();"> <div> One:<select id="test1"></select><br> Two:<select id="test2"></select> </div> <br><br><br> <div> <table> <tr> <td>Three:</td> <td><select id="test3"></select></td> </tr> <tr> <td>Four:</td> <td><select id="test4"></select></td> </tr> </table> </div> </body> </html>