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
The_FoxThe_Fox 

Resusable query and delete function in JS

Hello

Feel free to improve it and then share it with everybody

Please replace [ and ] where you normally should have < and > (that is on html or xml tags

Code guys

[!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"]
[html]
[head]

[title][/title]
[script language="JavaScript"]
[!--
var sessionid = "{!API_Session_ID}";
var apiServer = "{!API_Enterprise_Server_URL_50}";
var SoapHeader = "[?xml version=\"1.0\" encoding=\"UTF-8\"?]";
SoapHeader += "[soapenv:Envelope xmlns:soapenv=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"]";
SoapHeader += "[soapenv:Header]";
SoapHeader += "[ns1:SessionHeader soapenv:mustUnderstand=\"0\" xmlns:ns1=\"urn:enterprise.soap.sforce.com\"]";
SoapHeader += "[ns2:sessionId xmlns:ns2=\"urn:enterprise.soap.sforce.com\"]" + sessionid + "[/ns2:sessionId]";
SoapHeader += "[/ns1:SessionHeader]";
SoapHeader += "[/soapenv:Header]";
SoapHeader += "[soapenv:Body]";

var SoapFooter = "[/soapenv:Body]";
SoapFooter += "[/soapenv:Envelope]";

var agt = navigator.userAgent.toLowerCase();
var is_gecko = (agt.indexOf('gecko') != -1);
var is_ie = (agt.indexOf("msie") != -1);
// This will be a double dimension array of objects called Record (Record could be seen has a salesforce object)
var Results = new Array();

//here I create the XML Http Request
if (is_ie){
var xmlReq = new ActiveXObject("Microsoft.XMLHTTP");}
else { var xmlReq = new XMLHttpRequest(); }

//here I create the salesforce object with only id as property for the moment
function Record()
{
this.Id = '';
}

//You have to send an array of Ids to this function and the objects are deleted provided you have the right to do so
function deleteId(ids)
{

var delCommand = SoapHeader;
delCommand += "[delete xmlns=\"urn:enterprise.soap.sforce.com\"]";
for (var j=0;j {
delCommand += "[ids]" + ids[j] + "[/ids]";
}

delCommand += "[/delete]";
delCommand += SoapFooter;
xmlReq.open("POST", apiServer, false);
xmlReq.setRequestHeader("Content-Type","text/xml");
xmlReq.setRequestHeader("SOAPaction","delete");
xmlReq.send(delCommand);
}

/*Here you have a standard query in javascript
you have to pass the queryname as a String
fields as an Array of the field you want in your Select
sfoject as a String representing the Salesforce Object
whereclause as a string with your clause already built (without the where)*/
function query(qryname, fields,sfobject,whereclause)
{
var fieldstring = "";
for (var j=0;j if (fieldstring == "") {fieldstring = fields[j] ;}
else {fieldstring += "," + fields[j];};
}
var queryCommand = SoapHeader;
queryCommand += "[query xmlns=\"urn:enterprise.soap.sforce.com\"]";
if (whereclause=="") {
queryCommand += "[queryString]Select " + fieldstring + " from " + sfobject + "[/queryString]";
}
else {
queryCommand += "[queryString]Select " + fieldstring + " from " + sfobject + " where " + whereclause + "[/queryString]";
}
queryCommand += "[/query]";
queryCommand += SoapFooter;
xmlReq.open("POST", apiServer, false);
xmlReq.setRequestHeader("Content-Type","text/xml");
xmlReq.setRequestHeader("SOAPaction","query");
xmlReq.send(queryCommand);
// here I am going to the root element
var xmlDoc = xmlReq.responseXML.documentElement;
// I am going to the parent of the results
var objNodeList = xmlDoc.getElementsByTagName("records");
var sfid = "";
for (var j=0;j for (var k =0;k if (is_ie) {
var field = objNodeList.item(j).childNodes.item(k).text;}
else {
if (objNodeList.item(j).childNodes.item(k).childNodes.length>0)
{var field = objNodeList.item(j).childNodes.item(k).firstChild.nodeValue;}
}
switch(objNodeList.item(j).childNodes.item(k).nodeName)
{
case "sf:Id":
// Here I create a new object and the array Results[qryname] get a new entry each time an id is discovered
Results[qryname][field] = new Record;
for (var x=1;x Results[qryname][field][fields[x]]=''; //here I extend the properties of the ojbect record with all the fields
}
Results[qryname][field].Id = field;
sfid = field;
break;
default :
if (objNodeList.item(j).childNodes.item(k).nodeName.substring(0,3) == 'sf:') {
node = objNodeList.item(j).childNodes.item(k).nodeName.substring(3,objNodeList.item(j).childNodes.item(k).nodeName.length);
Results[qryname][sfid][node]= field; //here I fill the properties with the matching values coming from salesforce.com
}
break;

}
}
}
}

var fld = new Array();
// exemple for Account object: I create an array Results['Account'] to store the results send by my query on Account
Results['Account'] = new Array();
// here I create the field list
//IMPORTANT: Please always include the Id Field
fld = ['Id','Name','Site'];
//Here I am constructing my clause (AccountId here is a variable)
clause = "Id = '" + AccountId + "'";
//here I am making my query
query('Account',fld,'Account', clause);
var AcctInfo = "";
//I browse through my results
for (var x in Results['Account'])
{
AcctInfo += Results['Account'][x].Name + " " + Results['Account'][x].Site;
}
/*
In fact with this snippet and the construction of the multidimensionnal array Results you can store all the results of you query so that you can retrieve them later on in th code.

*/
// here an example of the combined use of delete and query function
var deleteids = new Array();
Results['Task'] = new Array;
clause = "WhoId='00320000002Ece0'";
fld = ['Id'];
query('Task',fld,'Task',clause);
var j=0;
for (var x in Results['Task'])
{
deleteids [j] = Results['Task'][x].Id;
j++;
}
deleteId(deleteids);
[/script]
[/body]
[/html]
benjasikbenjasik
Nice work! Now we just need a shared JS file with all the functions (create, update, delete, query) that could be upgraded and shared by many We're getting closer.
The_FoxThe_Fox
Hi Benji,

We need the retrieve as well and dealing with responseXMl with faulty message just in case. I think (thanks to henry Hess) I should separate and have something like query and getqueryresults or even more broader application a get results. I will try to work on this one but I have little time to do so.

Regards
DevAngelDevAngel

How about interacting with sforce like this in JS:


function doit() {
  if (window.XMLHttpRequest) {
  //Need to do some security stuff for Mozilla
    netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
  }
  //Do a login call
  var loggedInOk = doLogin(document.log.usern.value, document.log.pwrd.value);

  if ( loggedInOk ) {
    var msg = document.getElementById("content");
    msg.style.visibility = "visible";
    var soql = prompt("Enter a SOQL statement:", "not");
    if (soql != "not") {
      //Execute a query of the user's choosing.
      var records = doQuery(soql);

      //The DynaBeans returned have a html output method
      for (var i=0;i msg.innerHTML = msg.innerHTML + records[i].toHTMLString();
    }

    msg.innerHTML = msg.innerHTML + "****************************************************************<BR><BR>";
    //To access the beans individually and use the properties
    for (var i=0;i //write out a record number
      msg.innerHTML = msg.innerHTML + "Record: " + (i + 1).toString() + "<BR>";
      var spacer = "    ";
       // get a bean
       var bean = records[i];

       //get the properties
       var props = bean.getProperties();

      //Iterate the keys of the properties hash
      for (key in props) {
         //get a prop
         var prop = bean.getProperty(key);
        //get a value
        var val = prop.getValue();
        //get the name of the prop
        var name = prop.getName();
        //Spit out some results
        msg.innerHTML = msg.innerHTML + spacer + "propName = " + name + ", value is: " + val + "<BR>";
       }
     }
  }

  if (confirm("Do you want to create 2 contacts?")) {
    var contact = new Array();
    contact[0] = new DynaBean("Contact");
    contact[0].setProperty("FirstName", "Dave");
    contact[0].setProperty("LastName", "Carroll");
    contact[1] = new DynaBean("Contact");
    contact[1].setProperty("FirstName", "Dave2");
    contact[1].setProperty("LastName", "Carroll2");
 
    var saveResult = doCreate(contact);
    for (var i=0;i

content.innerHTML = content.innerHTML + saveResult[i].toHTMLString();
 }
}
}

DevAngelDevAngel

Sorry for the cryptic post.  What I mean to do was give a peak at a library I'm working on the is a javascript implementation of DynaBeans.  The main idea here is that you do a serialization process in javascript using user objects, sometimes called associative arrays.  So when you make a query, you generate the appropriate soap message and, using DOM, put the results into a collection of "DynaBeans".  This is simple since to create a key/value pair for a javascript object you just ref the object and set the value (object[sforceFieldname] = sforceValue).

Once you have the function to serialize the soap response to a "DynaBean", the next step is to serialize a "DynaBean" to a soap request such as create or update.  This is pretty easy and can even be a user defined method that is a member of the "DynaBean" implementation.  This would allow syntax like:

var contact = new DynaBean("Contact");

contact.setProperty("FirstName", "Dave");

contact.setProperty("LastName", "Carroll");

and so on.  Since an object has a single representation in SOAP for both update and create we can code that serialization simply.

Now, combine these ideas with a wrapper that sends messages and dispatches responses to user defined handlers and we get to do something like:

contact = doUpdate(contact);

This method would run the update call and on the response if it were successful, add an Id field to the contact dynabean, and if not add an errors field instead.  Then we would be able to do this:

if (contact.getPropertyValue("success")  == "true") {

    alert("The contact created has an id of: " + contact.getPropertyValue("Id"));

} else {

    alert("There was an error with the create call: " + contact.getPropertyValue("errors").toString());

}

The wrapper also should (and does) use XmlHTTPRequest object and the activex version if it's IE making it compatible with mozilla and ie.

Cheers

 

 

Message Edited by DevAngel on 06-17-2005 08:18 AM