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
AnnieGAnnieG 

Scontrol: QueryResult.loadSelectElement function

Hi,
       Anyone who has the experience of using the QueryResult.loadSelectElement function please take a look at my code:

           function setup() {

                var queryResult = sforceClient.query("Select Id, LastName, FirstName From Lead ");
    //            var t1 = document.getElementById("select1");

                queryResult.loadSelectElement("select1", true, "id", "LastName","FirstName LastName ");
            }

            <select id ="select1" >            
            </select>

        According to http://blog.sforce.com/sforce/2006/04/ajax_toolkit_be.html, Want to create a drop down list (select element) from the results of a query?  No problem.  Just run your query and call the QueryResult's loadSelectElement method.  This method takes the id of your select element and populates the options collection from the query result.  You specify which field is used the option value, which field or fields to use for the display values, whether you want the list sorted or not and optionally how you want the display values formated.

           But I can't get my code to work, any suggestion? Thanks a lot for your sharing!

Annie
DevAngelDevAngel
Hi AnnieG,

What error if any are you getting?

To use this method you need to add ?browser=true to the url for the toolkit.

<script language="javascript" src="https://www.salesforce.com/services/lib/ajax/beta3.3/sforceclient.js?browser=true" type="text/javascript"></script>

Cheers
AnnieGAnnieG
Hi,
       Thanks for your reply!
       Yes, I have included the exact script line in my code.
       I have not got any error message, but my drop down list hasn't been populated with the options retrived from the query result. That is to say the list is empty.
       Just don't know why.
       Thanks again!
Annie
     
DevAngelDevAngel
Hi AnnieG,

Try running this as an html page from your local drive.  When the page loads, enter your user name and password.  After succussful login select case from the list of record types.

The second list uses the loadSelectElement function. 

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>

var objectId = "001300000077rBf";
var objectType = "Account";

function initPage() {
 sforceClient.useCookies = true;
 sforceClient.registerInitCallback(setup);
 sforceClient.init("{!API_Session_ID}", "{!API_Partner_Server_URL_60}", true);
}
function setup() {
 sforceClient.DescribeGlobal(describeGlobalCallback);
}
function describeGlobalCallback(dg) {
 var sel = document.getElementById("cboType");
 sel.options.length = 0;
 for (var i=0;i<dg.types.length;i++) {
  var opt = document.createElement("OPTION");
  opt.value = dg.types[i];
  //opt.text = dg.types[i];
  opt.appendChild(document.createTextNode(dg.types[i]));
  sel.appendChild(opt);
 }
}
var lastDate = null;

function formatMyDate() {
 var date = new Date();
 if (lastDate != null) {
  var elapsed = date.getTime() - lastDate.getTime();
  elapsed;
 }
 var out = "[" + date.getFullYear();
 out += "-" + (date.getMonth() + 1).toString().padLeft("0", 2);
 out += "-" + (date.getDate()).toString().padLeft("0", 2);
 out += " " + date.getHours().toString().padLeft("0", 2);
 out += ":" + date.getMinutes().toString().padLeft("0", 2);
 out += ":" + date.getSeconds().toString().padLeft("0", 2);
 out += "." + date.getMilliseconds().toString().padLeft("0", 3);
 out += "] ";
 if (lastDate != null) {
  out += "(" + elapsed / 1000 + ") ";
 }
 lastDate = date;
 return out;
};
var obj;
function btnDoLayout_onclick() {
 if (objectId == "empty") return;
 //sforceClient.debuglog.writeln(formatMyDate() + "onclick entered...");
 if (document.getElementById("tableLayout_007") != undefined) {
  document.body.removeChild(document.getElementById("tableLayout_007"));
  document.body.removeChild(document.getElementById("layouthr"));
 }
 var hr = document.createElement("HR");
 hr.id = "layouthr";
 document.body.appendChild(hr);
 var where = "id = '" + objectId + "'";
 
 //sforceClient.debuglog.writeln(formatMyDate() + "query for object...");
 obj = sforceClient.Query("Select " + sforceClient.DescribeSObject(objectType).fieldList + " From " + objectType + " Where " + where).records[0];
 //sforceClient.debuglog.writeln(formatMyDate() + "query returned...");
 //sforceClient.debuglog.writeln(formatMyDate() + "calling layout...");
 var t = obj.layoutPage();
 //sforceClient.debuglog.writeln(formatMyDate() + "layout returned...");
 document.body.appendChild(t);
}

//-->
  </script>
  <script language="javascript" id="clientEventHandlersJS">
<!--
layoutReturned = false;
describeReturned = false;

function cboType_onclick(opt) {
 //sforceClient.debuglog.clear();
 layoutReturned = false;
 describeReturned = false;
 //sforceClient.debuglog.writeln(formatMyDate() + "Calling describe layout...");
 sforceClient.DescribeLayout(opt.value, describeLOCallback);
 //sforceClient.debuglog.writeln(formatMyDate() + "Calling describe...");
 sforceClient.DescribeSObject(opt.value, describeCallback);
 //sforceClient.debuglog.writeln(formatMyDate() + "exiting cboType_onclick...");
}
function describeCallback(qr) {
 describeReturned = true;
 //sforceClient.debuglog.writeln(formatMyDate() + "   describeReturned = " + describeReturned + "...");
 if (layoutReturned == true) {
  getChildren();
 }
}
function describeLOCallback(qr) {
 layoutReturned  = true;
 //sforceClient.debuglog.writeln(formatMyDate() + "   layoutReturned = " + layoutReturned + "...");
 if (describeReturned == true) {
  getChildren();
 }
}
function getChildren() {
 var cbo = document.getElementById("cboType");
 var opt = cbo.options[cbo.selectedIndex];
 if (sforceClient.describeSObject(opt.value).layoutable == true) { 
  sforceClient.setBatchSize(10);
  objectType = opt.value;
  sforceClient.Query("Select " + sforceClient.DescribeSObject(opt.value).fieldList + " From " + opt.value, getChildrenCallback);
 } else {
  document.getElementById("cboObject").options.length = 0;
  var copt = document.createElement("option");
  copt.value = "empty";
  copt.appendChild(document.createTextNode("<not layoutable>"));
  document.getElementById("cboObject").appendChild(copt);
 }
}
function btnShow_onclick() {
 sforceClient.debuglog.show();
 sforceClient.debuglog.writeln(obj);
}
function getChildrenCallback(qr) {
 var cbo = document.getElementById("cboType");
 var opt = cbo.options[cbo.selectedIndex];
 qr.loadSelectElement("cboObject", true, "id", sforceClient.DescribeSObject(opt.value).getNameField());
 objectId = document.getElementById("cboObject").options[0].value;
 btnDoLayout_onclick();
}
//-->
  </script>
 </head>
 <body onload="initPage()" ms_positioning="GridLayout">
  <P>Select a record type:&nbsp;&nbsp;
   <SELECT language="javascript" id="cboType" style="WIDTH: 168px" onchange="return cboType_onclick(this.options[this.selectedIndex])"
    name="Select1">
    <OPTION selected></OPTION>
   </SELECT>
  </P>
  <P>Select an object:&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
   <SELECT language="javascript" id="cboObject" style="WIDTH: 168px" onchange="objectId = this.options[this.selectedIndex].value; btnDoLayout_onclick(); return true;"
    name="Select1">
    <OPTION selected></OPTION>
   </SELECT>
   <INPUT language="javascript" id="btnShow" style="Z-INDEX: 101; LEFT: 326px; POSITION: absolute; TOP: 14px"
    onclick="return btnShow_onclick()" type="button" value="Show Dynabean Values" name="Button1"></P>
 </body>
</html>

 

AnnieGAnnieG
Hi, DevAngel:
           Thanks for your help and code!
           If I understand you correctly, I should copy your code and make it a s-control (saved as an html file) in my sandbox and activate it with a link or a tab, right? So I did. And I wasn't prompted for the user name and password since I logged in. But the lists are empty.
           Am I following you? Thanks again!
           Without getting the loadSelectElement method to work, I had to write javascript functions to implement the whole algorithm, like putting together and sort an two dimenssional array,  it worked.  But I still hope there is a better solution.
          
DevAngelDevAngel
Nope, the file should be saved to your local drive and run from there.  It can be run as an scontrol, in which case you would not get the login dialog (already logged in with an scontrol) and would need to edit a couple of hard coded ids.

This is a test file that I've used in the past and is not really meant to do anything other than verify that it works.

Cheers
AnnieGAnnieG
Hi, DevAngel:

      I did what you tell me to. Save it as an html file, launch it from windows explorer, but it just shows two empty lists with a button, not even prompting me to log in. When I click the button, the lists are not populated. Am I doing wrong again? Thanks!
DevAngelDevAngel
Is there a security warning in IE?  I believe you have to explicitly tell IE that you will allow javascript to run from local files.
AnnieGAnnieG
Hi, DevAngel:
        There was no error message when I launch the page either from FireFox or IE. Thanks!
DevAngelDevAngel
Oh well, I guess it's not that portable!  You might be able to get it to work as an scontrol.  In any case, search the file for loadForSelect and you can see a simple usage of the method.  In yours you can try using the simple parameter list (ie just display the last name field).

I'll try and get your query to work and send you the snippet.


Cheers
DevAngelDevAngel
So, turns out that function has a bug in it for sorting.  Try yours again with sorting turned off.

I've included an scontrol body that has an override for the loadSelectElement function that sorts properly based on the option text of the resultant select element.  Also are a couple examples of how the super simple formatting works.

Cheers.

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>

function initPage() {
 sforceClient.useCookies = true;
 sforceClient.init("{!API_Session_ID}", "{!API_Partner_Server_URL_60}", true);
}
function loadLeads() {
    var leads = sforceClient.Query("Select Id, FirstName, LastName From Lead");
    leads.loadSelectElement("select1", true, "id", ["LastName", "FirstName"], "FirstName LastName");
    leads.loadSelectElement("select2", true, "id", "LastName");
    leads.loadSelectElement("select3", true, "id", "FirstName");
    leads.loadSelectElement("select4", true, "id", ["LastName", "FirstName"], "FirstName (LastName)");
}

Sforce.QueryResult.prototype.loadSelectElement = function(selectElement, sorted, valueField, displayField, formatString) {
 this.sortf = function(x, y) {
  if (x.sortVal < y.sortVal) {
   return -1;
  } else if (x.sortVal == y.sortVal) {
   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) {
      df = this.records[i].get(displayField[j]);
     } else {
      df = df.replace(regex, this.records[i].get(displayField[j]));
     }
    }
   } else {
    var df = this.records[i].get(displayField);
   }
   var opt = adoc.createElement("OPTION");
   opt.value = vf;
   //opt.text = df;
   opt["sortVal"] = df.toLowerCase();
   opt.appendChild(adoc.createTextNode(df));
   opt.record = this.records[i];
   options.push(opt);
  }
  if (sorted && sorted == true) {
   options = options.sort(this.sortf);
  }
  for (key in options) {
   sel.appendChild(options[key]);
  }
  return;
 } else {
  return;
 }
};
//-->
  </script>
 </head>
 <body onload="initPage()" ms_positioning="GridLayout" style="position: absolute">
        <div style="postion: absolute">
         <input value="Load Lead List" type="button" onclick="javascript: loadLeads();" style="left: 32px; width: 128px; position: absolute; top: 8px" />
         <select id="select1" style="left: 32px; width: 128px; position: absolute; top: 40px"></select>
            <select id="select3" style="left: 32px; width: 128px; position: absolute; top: 104px"></select>
            <select id="select4" style="left: 32px; width: 128px; position: absolute; top: 136px"></select>
            <select id="select2" style="left: 32px; width: 128px; position: absolute; top: 72px"></select>
        </div>
 </body>
</html>

 

SteveBowerSteveBower
Hi Annie, if you're willing to try something different, cut and past the following code into your s-control after the <script> tag that includes sforceclient.js.  It overrides the salesforce-provided loadSelectElement with a slightly modified version.

Let me know if it works for you.  Steve.


Code:
<script type="text/javascript">
Sforce.QueryResult.prototype.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>

 

DevAngelDevAngel
Thanks for the update Steve.  You may as well nuke the "old code" parts.
 
Cheers
SteveBowerSteveBower

By the way Annie, a more detailed example and explanation of my code changes is here:

http://community.salesforce.com/sforce/board/message?board.id=ajax_toolkit&message.id=626&query.id=14838#M626

Good luck, Steve.