You need to sign in to do that
Don't have an account?

Dependent Picklists
I found myself needing to implement Dependent Picklists in a UI I'm working on. However, as has been noted in other threads, dependent picklists aren't actually implemented in the Ajax Beta 3.3 Toolkit. So, I went and got them working. Here's what I implemented. I welcome any comments, critiques, suggestions, etc.
Frankly, there have been a lot of bugs and code fixes submitted by people on these boards, I REALLY think it's time for a Beta 4.0, or, god forbid, a Production version of the Ajax toolkit.
I hope this helps some of you, thanks, Steve Bower.
(In general, I make changes by overriding code in sforceClient.js by inserting my own changed code after the "<script src=...sforceClient.js> tag. )
First, this block can be added to the sforceClient.js section where the other prototypes for PicklistEntry are defined. Somewhere around line 2530.
Note: I know that the sample code for the Java version used a bitmask of 0x80 before shifting it. That just didn't work for me, it was off by one. So, it's possible I've done something wrong here, but this code is working fine.
Code:
Now, as someone else noted, the "validFor" value in the picklistEntry's that are being returned in a Sforce.DescribeSObjectResult object appear to be missing. That's because they are. So, we need to add some code to the createPicklistValues function that is defined in the DescribeSObjectResult function definition. I'd say "around" line 2316, however in actuality the entire createPicklistValues function is defined on that one line in one huge run-on line of code. Either way, you want to add:
Code:
Ok, so now you have data in the fields and methods to access it.
All you need is a code example which shows how to use it. In the sample
provided for Java, they are building a matrix by going "across" one
picklistEntry at a time and determining it's status for each bit.
All I really wanted was some code to generate a new Options array
for an element depending on the index of the controlling field
which I would pass in. So, yes, I'm expensivly rebuilding my
Options lists whenever needed instead of building a cached array
of Select Option arrays and then referring to them, but this is
fine for this particular usage.
Sample:
I appreciate any feedback, comments, tips, improvements, etc. Thanks, Steve.
Frankly, there have been a lot of bugs and code fixes submitted by people on these boards, I REALLY think it's time for a Beta 4.0, or, god forbid, a Production version of the Ajax toolkit.
I hope this helps some of you, thanks, Steve Bower.
(In general, I make changes by overriding code in sforceClient.js by inserting my own changed code after the "<script src=...sforceClient.js> tag. )
First, this block can be added to the sforceClient.js section where the other prototypes for PicklistEntry are defined. Somewhere around line 2530.
Note: I know that the sample code for the Java version used a bitmask of 0x80 before shifting it. That just didn't work for me, it was off by one. So, it's possible I've done something wrong here, but this code is working fine.
Code:
Sforce.PicklistEntry.prototype.getValidFor = function() { return this.validFor; } Sforce.PicklistEntry.prototype.getLabel = function() { return this.label; } Sforce.PicklistEntry.prototype.getValue = function() { return this.value; } Sforce.PicklistEntry.prototype.isValidFor = function(n) { // ValidFor is a bitmap. Each bit corresponds to an entry in the controlling // picklist, so if the Controlling field has 0=colors 1=tastes, then this // validFor field will have two significant bits indicating if this PicklistEntry // is valid for each of the two categories. Reading left to right, the first // bit indicates if this entry is valid for Colors, and the next bit for Tastes. // // First isolate which number in the array we want to inspect by dividing // the index we're looking for by 8. (n>>3 is a bitwise divide by 8). // Now we have the number, we need to figure out which single bit to mask off. // This would be the remainder after the divide by 8. Build a mask for it. // Note: using 0x40 instead of 0x80 seems to work for me. 0x80 was off. return (((0x40 >> (n%8)) & (this.validFor[(n>>3)])) != 0); }
Now, as someone else noted, the "validFor" value in the picklistEntry's that are being returned in a Sforce.DescribeSObjectResult object appear to be missing. That's because they are. So, we need to add some code to the createPicklistValues function that is defined in the DescribeSObjectResult function definition. I'd say "around" line 2316, however in actuality the entire createPicklistValues function is defined on that one line in one huge run-on line of code. Either way, you want to add:
Code:
picklistEntry.validFor = [0,0,0,0]; // vFor is a four character string holding the bitset. var vFor = Sforce.DOM.GetElementValue (node[i], "validFor"); if (vFor != "" && vFor != null ) { for (var j=0;j<vFor.length;j++) { // Convert the letters to a numeric array so bitwise // operations are possible. var n = vFor.charCodeAt(j); picklistEntry.validFor[j] = n; } }
into the function. So createPickListValues ends up looking like:
Code:
createPicklistValues = function(node) { if (node.length == 0) { return new Array(); } else { var ret = new Array(); for (var i=0;i<node.length;i++) { var picklistEntry = new Sforce.PicklistEntry(); picklistEntry.active = Sforce.DOM.GetBool(Sforce.DOM.GetElementValue (node[i], "active")); picklistEntry.defaultValue = Sforce.DOM.GetBool(Sforce.DOM.GetElementValue (node[i], "defaultValue")); picklistEntry.label = Sforce.DOM.GetElementValue (node[i], "label"); picklistEntry.value = Sforce.DOM.GetElementValue (node[i], "value"); picklistEntry.validFor = [0,0,0,0]; // vFor is a four character string holding the bitset. var vFor = Sforce.DOM.GetElementValue (node[i], "validFor"); if (vFor != "" && vFor != null ) { for (var j=0;j<vFor.length;j++) { // Convert the letters to a numeric array so bitwise // operations are possible. var n = vFor.charCodeAt(j); picklistEntry.validFor[j] = n; } } ret[i] = picklistEntry; } return ret; } };
Ok, so now you have data in the fields and methods to access it.
All you need is a code example which shows how to use it. In the sample
provided for Java, they are building a matrix by going "across" one
picklistEntry at a time and determining it's status for each bit.
All I really wanted was some code to generate a new Options array
for an element depending on the index of the controlling field
which I would pass in. So, yes, I'm expensivly rebuilding my
Options lists whenever needed instead of building a cached array
of Select Option arrays and then referring to them, but this is
fine for this particular usage.
Sample:
function reloadDependentPicklistElement(element,bean,fld,depIndex) { /* element: the DOM element we are going to create a new Option list for. It should be a Select element, we aren't checking that. bean: the type of bean we are looking at: "opportunity", "account", etc. fld: the field in the bean we are building a picklist from. This should obviously be a picklist type field but we aren't checking that. depIndex: the index into the Controller Picklist that we are testing. (Normally this will come from a nearby DOM controllerElement.indexSelected type of construct.) Returns an Options array loaded into the requested Element. */ var j = bean.fieldMap.getItem(fld); var startopt = 0; element.options.length = 0; for (var i=0; i < j.picklistValues.length; i++) { var plv = j.picklistValues[i]; if (j.dependentPicklist == true) { if (plv.isValidFor(depIndex)) { element.options[startopt++] = new Option(plv.label,plv.value); } } else { element.options[startopt++] = new Option(plv.label,plv.value); } if (plv.defaultValue == true) { element.options[startopt-1].selected = true element.selectedIndex = startopt-1; // this one. } } element.options.length = startopt; }
I appreciate any feedback, comments, tips, improvements, etc. Thanks, Steve.
Simon, I'm not positive it's a bug in ValidFor. It may be something I'm doing wrong... I used Steve's technique above to build a dependent picklist but I didn't override validFor the way he did because I was getting some values back whereas earlier posts weren't getting any values.... should i be overridding validFor and if so, how do I do this in my scontrol using 8.0? i searched connection.ps but wasn't able to find any definition for PicklistEntry or the validFor function... Where is this defined? here is the code snippet to build my dependent picklist from the describe call. Am I doing something wrong here?
Code:
Message Edited by gsickal on 03-08-2007 01:05 PM
Steve, maybe you could might be so kind as to take a quick look at this. I have spent countless hours trying to debug the problem without success... You can easily duplicate the problem i this way:
(1) create a controller picklist and add values C1,C2,C3,C4
(2) create a dependent picklist and add values D1A, D1B, D1C, D2A, D2B, D2C, D3A, D3B, D3C, D4A, D4B, D4C. Assign D1x to C1, D2x to C2, D3x to C3, and D4x to C4.
(3) show the picklists using your code and everything works okay except for the C1 which picks up the 3 values for D1A,D1B,D1C in addition to the ones it should get for C4. It appears this is because the validFor value I get back is 103 but should be 97... Do you concur? Is this a validFor error or an error in ,your original implementation?
Also Simon, I created a case for this yesterday, the number is Case 01150344:API call error, perhaps if y7ou could you might take a quick look? Thank yoou very much
Message Edited by gsickal on 03-09-2007 09:29 AM
// assume dep is the Field object for the dependent picklist field and
// ctrl is the Field object for the controlling field.
var b64 = new sforce.Base64Binary("");
for (var i =0; i <dep.picklistValues.length; i++) {
var ple = dep.picklistValues[i];
var ln = ple.label + " ";
var vf = b64.decode(ple.validFor);
for (var j = 0; j < ctrl.picklistValues.length; j++) {
var bits = vf.charCodeAt(j >> 3);
if ((bits & (0x80 >> j)) != 0)
ln += "x ";
else
ln += " ";
}
output.innerHTML += ln + "<br>";
}
Cheers
Simon
Message Edited by zak on 03-11-2007 01:45 PM
Hi all,
I am also getting same problem, where i am not getting the values of validFor property of the picklist values. Its returning me empty.
So hw should i get those things so that i will able to use above code snippest for the Dependant picklist values. Which will provide me the UI design by SControl for controlling and controlled field on the page.
Thanks in Advance.
Thnaks a lot, I don't know how I would have figured that out with you! One slight correction, in bold below.
for (var j = 0; j < ctrl.picklistValues.length; j++) {
var bits = vf.charCodeAt(j >> 3);
if ((bits & (0x80 >> (j%8))) != 0)
ln += "x ";
else
ln += " ";
}