Is CAMLQuery parameter dynamic?

Feb 7, 2012 at 12:41 PM
Edited Feb 7, 2012 at 1:35 PM

Hi,

Is the CAMLQuery parameter dynamic?
I have the following code:

 // Relation between Client & Project
 $().SPServices.SPCascadeDropdowns({
  relationshipList: "{84CF1751-36DD-446E-B99E-C6042B1C0DFF}", //Projects
  relationshipListParentColumn: "InternalClient",
  relationshipListChildColumn: "Title",
  parentColumn: "Client",
  childColumn: "Project",
  CAMLQuery: "<Eq><FieldRef Name='LocationInternalClient'/><Value Type='Text'>" + oCascadeData.Country + "</Value></Eq>",
  completefunc: function() {

   alert(oCascadeData.Country);
  },
  debug: true
 });

The desired result is not given, I get a empty resultset.

But when I change the CAMLQuery parameter to one with a hardcoded value, I get the desired result:

CAMLQuery: "<Eq><FieldRef Name='LocationInternalClient'/><Value Type='Text'>France</Value></Eq>",

And I'm quite sure the oCascadeData.Country variable is properly set because the alert gives me 'France'...

 

Coordinator
Feb 7, 2012 at 2:36 PM
Edited Feb 7, 2012 at 2:36 PM

Ernst:

The CAMLQuery is essentially a constant once the SPCascadeDropdowns function is called. That is, the variable won't be reevaluated upon a parent dropdown change. So if oCascadeData.Country doesn't have a value when you call SPCascadeDropdowns, then you won't get any results.

It may well be that you can accomplish what you want by rethinking your parent/child relationships, but I can't tell with the details above.

M.

Feb 7, 2012 at 4:38 PM
Edited Feb 7, 2012 at 5:46 PM

I ran across the same issue.  So I made my dynamic.  Basically I followed these steps:

In the $(document).ready() function I added code to inject several checkboxes for predefined filtering options and bound another function to the click events of those checkboxes.  Something like the following (pardon the formatting, but the insert code snippet feature does not appear to work for me):

  var target = $("select[id$='SelectCandidate'][Title^='myMultiSelectFieldName']");
  var filters =
  $(
   "<tr><td colspan='5' class='ms-formbody' vAlign='top' style='border-style:none;padding-left:0px;padding-top:0px'>Filter By: "
   + "<label for='myFilter01'><input type='checkbox' id='myFilter01' checked='checked' />Filter #1</label>"
   + "&nbsp<label for='myFilter02'><input type='checkbox' id='myFilter02' checked='checked' />Filter #2</label>"
   + "</td></tr>"
  );
  target.closest("tbody").prepend(filters);
  $('#myFilter01').bind('click', applyFilters);
  $('#myFilter02').bind('click', applyFilters);

Now the tricky part was creating the CAML fragment properly.  I've learned I hate CAML and can't wait until I can move to using LINQ to generate my CAML :).  One caveat I found is if I changed the filters that also removed items already selected as well if they do not meet the new filter criteria.  So I came up with this snippet as part of my filter logic.  After I generate my CAML fragement to pass to the SPFilterDropDown method I add an OR condition using this logic (assume the predefined filters have already been used to generate a value for variable 'query'):

  var idValues = "";
  $("select[id$='SelectResult'][Title^='myMultiSelectFieldName'] > option").each(function() {
   idValues += "<Value Type='Counter'>" + $(this).attr("value") + "</Value>"
  });
  if (idValues.length != 0) {
   query += "<In><FieldRef Name='ID' /><Values>" + idValues + "</Values></In>";
   if (applyMyFilter01 || applyMyFilter01) {query = "<Or>" + query + "</Or>";};
  };

Then I just call the method:

  $().SPServices.SPFilterDropdown({
   relationshipList: "myList",
   relationshipListColumn: "My_x0020_Column",
   columnName: "My Column",
   CAMLQuery: query,
   completefunc: null,
   debug: true
  });

Note all the code that generates the CAML fragment is contained in the function I bound to the checkboxes - applyFilters.

Feb 18, 2012 at 4:16 PM

Thank you all for your replies.

Eventually, I decided to branch the code for SPCascadeDropdowns to a version that uses two parentcolumns. Works like a dream!

May 2, 2012 at 7:08 PM

Hi, would it be possible to share the code that uses two parent columns?  Thanks.

May 3, 2012 at 11:58 AM

Sure, where can I drop the code?

Coordinator
May 3, 2012 at 1:30 PM

You should be able to post the code here. The little icon at the right of the toolbar let's you format it in the appropriate language.

M.

May 8, 2012 at 7:09 AM

Well, I'll try... it's a lot of code to post in a reply :)

Note:
Even though I modified some SPServices code (SPCascadeDropdowns), you'll still need a reference to SPservices.

I introduced two extra fields:

  • relationshipListParentExtraColumn: "", // The internal name of the extra parent column in the relationship list that will provide part of the filter
  • parentExtraColumn: ""     // The display name of the extra parent column in the form that will provide part of the filter

These two fields are used to get the value of the second dropdown and add an extra filter in the CAML query. Quite simple, actually...

The code beneath includes the call when the DOM is ready to the customized SPCascadeDropdowns (renamed to SPCascadeDropdownsCUSTOM) for your understanding. In this case the list Projects is filtered by two parents: InternalClient & LocationInternalClient.

Good luck using this code!

Here's the code:

$(document).ready(function() {

	// Relation between Location & Client
	$().SPServices.SPCascadeDropdowns({
		relationshipList: "{26C83E90-3061-4C1D-BFD3-23D632A91461}",		//InternalClients
		relationshipListParentColumn: "Location",
		relationshipListChildColumn: "Title",
		parentColumn: "Location",
		childColumn: "Client",
		completefunc: function() {},
		debug: false
	});

	// Relation between Client & Project
	$().SPServices.SPCascadeDropdownsCUSTOM({
		relationshipList: "{84CF1751-36DD-446E-B99E-C6042B1C0DFF}",	//Projects
		relationshipListParentColumn: "InternalClient",
		relationshipListChildColumn: "Title",
		parentColumn: "Client",
		childColumn: "Project",
		completefunc: function() {},
		debug: true,
		relationshipListParentExtraColumn: "LocationInternalClient",
		parentExtraColumn: "Location"
	});

});

// Function to set up cascading dropdowns on a SharePoint form
// Include in Newform.aspx, EditForm.aspx, or any other customized form.
// ******************************************
// CUSTOMIZED FOR CUSTOM : USING 2(!) PARENT COLUMNS !!!!!!!!!!!!!!
// ******************************************
$.fn.SPServices.SPCascadeDropdownsCUSTOM = function(options) {

	var opt = $.extend({}, {
		relationshipWebURL: "",				// [Optional] The name of the Web (site) which contains the relationships list
		relationshipList: "",				// The name of the list which contains the parent/child relationships
		relationshipListParentColumn: "",	// The internal name of the parent column in the relationship list
		relationshipListChildColumn: "",	// The internal name of the child column in the relationship list
		relationshipListSortColumn: "",		// [Optional] If specified, sort the options in the dropdown by this column,
											// otherwise the options are sorted by relationshipListChildColumn
		parentColumn: "",					// The display name of the parent column in the form
		childColumn: "",					// The display name of the child column in the form
		listName: $().SPServices.SPListNameFromUrl(),		// The list the form is working with. This is useful if the form is not in the list context.
		CAMLQuery: "",						// [Optional] For power users, this CAML fragment will be Anded with the default query on the relatedList
		promptText: "Choose {0}...",		// [Optional] Text to use as prompt. If included, {0} will be replaced with the value of childColumn
		noneText: "(None)",					// [Optional] Text to use for the (None) selection. Provided for non-English language support.
		simpleChild: false, 				// [Optional] If set to true and childColumn is a complex dropdown, convert it to a simple dropdown
		selectSingleOption: false,			// [Optional] If set to true and there is only a single child option, select it
		completefunc: null,					// Function to call on completion of rendering the change.
		debug: false,						// If true, show error messages;if false, run silent
		
		//added for CUSTOM		
		relationshipListParentExtraColumn: "",	// The internal name of the extra parent column in the relationship list that will provide part of the filter
		parentExtraColumn: ""					// The display name of the extra parent column in the form that will provide part of the filter

	}, options);

	// Find the parent column's select (dropdown)
	var parentSelect = new dropdownCtl(opt.parentColumn);
	if(parentSelect.Obj.html() === null && opt.debug) {errBox("SPServices.SPCascadeDropdowns", "parentColumn: " + opt.parentColumn, "Column not found on page");return;}

	// Find the child column's select (dropdown)
	var childSelect = new dropdownCtl(opt.childColumn);
	if(childSelect.Obj.html() === null && opt.debug) {errBox("SPServices.SPCascadeDropdowns", "childColumn: " + opt.childColumn, "Column not found on page");return;}

	// If requested and the childColumn is a complex dropdown, convert to a simple dropdown
	if(opt.simpleChild === true && childSelect.Type === "C") {
		$().SPServices.SPComplexToSimpleDropdown({
			columnName: opt.childColumn
		});
		// Set the childSelect to reference the new simple dropdown
		childSelect = new dropdownCtl(opt.childColumn);
	}

	switch(parentSelect.Type) {
		// Plain old select
		case "S":
			parentSelect.Obj.bind("change", function() {
				cascadeDropdown(opt, childSelect);
			});
			// Fire the change to set the allowable values
			parentSelect.Obj.change();
			break;
		// Input / Select hybrid
		case "C":
			parentSelect.Obj.bind("propertychange", function() {
				cascadeDropdown(opt, childSelect);
			});
			// Fire the change to set the allowable values
			parentSelect.Obj.trigger("propertychange");
			break;
		// Multi-select hybrid
		case "M":
			// Handle the dblclick on the candidate select
			parentSelect.Obj.bind("dblclick", function() {
				cascadeDropdown(opt, childSelect);
			});
			// Handle the dblclick on the selected values
			parentSelections = parentSelect.Obj.closest("span").find("select[ID$='SelectResult'][Title^='" + opt.parentColumn + " ']");
			parentSelections.bind("dblclick", function() {
				cascadeDropdown(opt, childSelect);
			});
			// Handle a button click
			parentSelect.Obj.closest("span").find("button").each(function() {
				$(this).bind("click", function() {
					cascadeDropdown(opt, childSelect);
				});
			});
			// Fire the change to set the allowable values initially
			cascadeDropdown(opt, childSelect);
			break;
		default:
			break;
	}
}; // End $.fn.SPServices.SPCascadeDropdowns

function cascadeDropdown(opt, childSelect) {
	var choices = "";
	var childSelectSelected = null;
	var parentSelectSelected = [];
	var parentExtraSelectSelected = [];
	var master;
	var MultiLookupPickerdata;
	var newMultiLookupPickerdata;
	var childColumnRequired;
	var numChildOptions;
	var firstChildOptionId;
	var firstChildOptionValue;

	// Find the parent column's select (dropdown)
	var parentSelect = new dropdownCtl(opt.parentColumn);
	// Get the parent column selection(s)
	switch(parentSelect.Type) {
		case "S":
			parentSelectSelected.push(parentSelect.Obj.find("option:selected").text());
			break;
		case "C":
			parentSelectSelected.push(parentSelect.Obj.attr("value"));
			break;
		case "M":
			parentSelections = parentSelect.Obj.closest("span").find("select[ID$='SelectResult'][Title^='" + opt.parentColumn + " ']");
			$(parentSelections).find("option").each(function() {
				parentSelectSelected.push($(this).html());
			});
			break;
		default:
			break;
	}

	// Find the extra parent column's select (dropdown)
	var parentExtraSelect = new dropdownCtl(opt.parentExtraColumn);
	// Get the parent column selection(s)
	switch(parentExtraSelect.Type) {
		case "S":
			parentExtraSelectSelected.push(parentExtraSelect.Obj.find("option:selected").text());
			break;
		case "C":
			parentExtraSelectSelected.push(parentExtraSelect.Obj.attr("value"));
			break;
		case "M":
			parentExtraSelections = parentExtraSelect.Obj.closest("span").find("select[ID$='SelectResult'][Title^='" + opt.parentColumn + " ']");
			$(parentExtraSelections).find("option").each(function() {
				parentExtraSelectSelected.push($(this).html());
			});
			break;
		default:
			break;
	}

	// If the selection hasn't changed, then there's nothing to do right now.  This is useful to reduce
	// the number of Web Service calls when the parentSelect.Type = "C" or "M", as there are multiple propertychanges
	// which don't require any action.  The attribute will be unique per child column in case there are
	// multiple children for a given parent.
	var childColumnStatic = $().SPServices.SPGetStaticFromDisplay({
		listName: opt.listName,
		columnDisplayName: opt.childColumn
	});
	if(parentSelect.Obj.attr("SPCascadeDropdown_Selected_" + childColumnStatic) === parentSelectSelected.join(";#")) {
		return;
	}
	parentSelect.Obj.attr("SPCascadeDropdown_Selected_" + childColumnStatic, parentSelectSelected.join(";#"));

	// Get the current child column selection, if there is one
	switch(childSelect.Type) {
		case "S":
			childSelectSelected = childSelect.Obj.find("option:selected").val();
			break;
		case "C":
			childSelectSelected = childSelect.Obj.attr("value");
			break;
		case "M":
			MultiLookupPickerdata = childSelect.Obj.closest("span").find("input[name$='MultiLookupPicker$data']");
			master = window[childSelect.Obj.closest("tr").find("button[id$='AddButton']").attr("id").replace(/AddButton/,'MultiLookupPicker_m')];
			currentSelection = childSelect.Obj.closest("span").find("select[ID$='SelectResult'][Title^='" + opt.childColumn + " ']");
			// Clear the master
			master.data = "";
			break;
		default:
			break;
	}

	// When the parent column's selected option changes, get the matching items from the relationship list
	// Get the list items which match the current selection
	var sortColumn = (opt.relationshipListSortColumn.length > 0) ? opt.relationshipListSortColumn : opt.relationshipListChildColumn;
	var camlQuery = "<Query><OrderBy><FieldRef Name='" + sortColumn + "'/></OrderBy><Where>";
	if(opt.CAMLQuery.length > 0) {
		camlQuery += "<And>";
	}

	// Build up the criteria for inclusion
	if(parentSelectSelected.length === 0) {
		// Handle the case where no values are selected in multi-selects
		camlQuery += "<And><Eq><FieldRef Name='" + opt.relationshipListParentColumn + "'/><Value Type='Text'></Value></Eq>";
	} else if(parentSelectSelected.length === 1) {
		// Only one value is selected
		camlQuery += "<And><Eq><FieldRef Name='" + opt.relationshipListParentColumn + "'/><Value Type='Text'>" + escapeColumnValue(parentSelectSelected[0]) + "</Value></Eq>";
	}

	// Build up the EXTRA criteria for inclusion (CUSTOM modification)
	if(parentExtraSelectSelected.length === 0) {
		// Handle the case where no values are selected in multi-selects
		camlQuery += "<Eq><FieldRef Name='" + opt.relationshipListParentExtraColumn + "'/><Value Type='Text'></Value></Eq></And>";
	} else if(parentExtraSelectSelected.length === 1) {
		// Only one value is selected
		camlQuery += "<Eq><FieldRef Name='" + opt.relationshipListParentExtraColumn + "'/><Value Type='Text'>" + escapeColumnValue(parentExtraSelectSelected[0]) + "</Value></Eq></And>";
	}
	
	if(opt.CAMLQuery.length > 0) {
		camlQuery += opt.CAMLQuery + "</And>";
	}
	camlQuery += "</Where></Query>";

	// Get information about the childColumn from the current list
	$().SPServices({
		operation: "GetList",
		async: false,
		listName: opt.listName,
		completefunc: function(xData, Status) {
			$(xData.responseXML).find("Fields").each(function() {
				$(this).find("Field[DisplayName='" + opt.childColumn + "']").each(function() {
					// Determine whether childColumn is Required
					childColumnRequired = ($(this).attr("Required") === "TRUE") ? true : false;
					// Stop looking; we're done
					return false;
				});
			});
		}
	});
	
	$().SPServices({
		operation: "GetListItems",
		// Force sync so that we have the right values for the child column onchange trigger
		async: false,
		webURL: opt.relationshipWebURL,
		listName: opt.relationshipList,
		// Filter based on the currently selected parent column's value
		CAMLQuery: camlQuery,
		// Only get the parent and child columns
		CAMLViewFields: "<ViewFields><FieldRef Name='" + opt.relationshipListParentColumn + "' /><FieldRef Name='" + opt.relationshipListChildColumn + "' /></ViewFields>",
		// Override the default view rowlimit and get all appropriate rows
		CAMLRowLimit: 0,
		// Even though setting IncludeMandatoryColumns to FALSE doesn't work as the docs describe, it fixes a bug in GetListItems with mandatory multi-selects
		CAMLQueryOptions: "<QueryOptions><IncludeMandatoryColumns>FALSE</IncludeMandatoryColumns></QueryOptions>",
		completefunc: function(xData, Status) {
			$(xData.responseXML).find("faultcode").each(function() {
				if(opt.debug) {
					errBox("SPServices.SPCascadeDropdowns",
						"relationshipListParentColumn: " + opt.relationshipListParentColumn + " or " +
						"relationshipListChildColumn: " + opt.relationshipListChildColumn,
						"Not found in relationshipList " + opt.relationshipList);
				}
				return;
			});

			// Add an explanatory prompt
			switch(childSelect.Type) {
				case "S":
					// Remove all of the existing options
					$(childSelect.Obj).find("option").remove();
					// If the column is required or the promptText option is empty, don't add the prompt text
					if(!childColumnRequired && (opt.promptText.length > 0)) {
						childSelect.Obj.append("<option value='0'>" + opt.promptText.replace(/\{0\}/g, opt.childColumn) + "</option>");
					}
					break;
				case "C":
					// If the column is required, don't add the "(None)" option
					choices = childColumnRequired ? "" : opt.noneText + "|0";
					childSelect.Obj.attr("value", "");
					break;
				case "M":
					// Remove all of the existing options
					$(childSelect.Obj).find("option").remove();
					newMultiLookupPickerdata = "";
					break;
				default:
					break;
			}
			// Get the count of items returned and save it so that we can select if it's a single option 
			// The item count is stored thus: <rs:data ItemCount="1">
			numChildOptions = parseFloat($(xData.responseXML).SPFilterNode("rs:data").attr("ItemCount"));

			// Add an option for each child item
			$(xData.responseXML).SPFilterNode("z:row").each(function() {
				// If relationshipListChildColumn is a Lookup column, then the ID should be for the Lookup value,
				// else the ID of the relationshipList item
				var thisOptionId = ($(this).attr("ows_" + opt.relationshipListChildColumn).indexOf(";#") > 0) ?
						$(this).attr("ows_" + opt.relationshipListChildColumn).split(";#")[0] :
						$(this).attr("ows_ID");
				// If the relationshipListChildColumn is a calculated column, then the value isn't preceded by the ID,
				// but by the datatype.  In this case, thisOptionId should be the ID of the relationshipList item.
				if(isNaN(thisOptionId)) {
					thisOptionId = $(this).attr("ows_ID");
				}
				
				// If relationshipListChildColumn is a Lookup column, then strip off the leading ID;# on the value
				var thisOptionValue = ($(this).attr("ows_" + opt.relationshipListChildColumn).indexOf(";#") > 0) ?
						$(this).attr("ows_" + opt.relationshipListChildColumn).split(";#")[1] :
						$(this).attr("ows_" + opt.relationshipListChildColumn);
				
				// Save the id and value for the first child option in case we need to select it (selectSingleOption option is true)
				firstChildOptionId = thisOptionId;
				firstChildOptionValue = thisOptionValue;
				
				switch(childSelect.Type) {
					case "S":
						var selected = ($(this).attr("ows_ID") === childSelectSelected) ? " selected='selected'" : "";
						childSelect.Obj.append("<option" + selected + " value='" + thisOptionId + "'>" + thisOptionValue + "</option>");
						break;
					case "C":
						if (thisOptionValue === childSelectSelected) {
							childSelect.Obj.attr("value", childSelectSelected);
						}
						choices = choices + ((choices.length > 0) ? "|" : "") + thisOptionValue + "|" + thisOptionId;
						break;
					case "M":
						childSelect.Obj.append("<option value='" + thisOptionId + "'>" + thisOptionValue + "</option>");
						newMultiLookupPickerdata += thisOptionId + "|t" + thisOptionValue + "|t |t |t";
						break;
					default:
						break;
				}
			});

			switch(childSelect.Type) {
				case "S":
					childSelect.Obj.trigger("change");
					// If there is only one option and the selectSingleOption option is true, then select it
					if(numChildOptions === 1 && opt.selectSingleOption === true) {
						$(childSelect.Obj).find("option[value!='0']:first").attr("selected", "selected");
					}
					break;
				case "C":
					// Set the allowable choices
					childSelect.Obj.attr("choices", choices);
					// If there is only one option and the selectSingleOption option is true, then select it
					if(numChildOptions === 1 && opt.selectSingleOption === true) {
						// Set the input element value
						$(childSelect.Obj).attr("value", firstChildOptionValue);
						// Set the vlue of the optHid input element
						$("input[id='" + childSelect.Obj.attr("optHid") + "']").val(firstChildOptionId);
					}
					// Trigger a change so that SharePoint's scripts will fire on the events
					childSelect.Obj.trigger("propertychange");
					// If there's no selection, then remove the value in the associated hidden input element (optHid)
					if(childSelect.Obj.val() === "") $("input[id='" + childSelect.Obj.attr("optHid") + "']").val("");
					break;
				case "M":
					MultiLookupPickerdata.attr("value", newMultiLookupPickerdata);
					// Clear any prior selections that are no longer valid
					$(currentSelection).find("option").each(function() {
						var thisSelected = $(this);
						var thisValue = $(this).html();
						$(this).attr("selected", "selected");
						$(childSelect.Obj).find("option:contains('" + thisValue + "')").each(function() {
							if($(this).html() === thisValue) {
								thisSelected.removeAttr("selected");
							}
						});
					});
					GipRemoveSelectedItems(master);
					// Hide any options in the candidate list which are already selected
					$(childSelect.Obj).find("option").each(function() {
						var thisSelected = $(this);
						$(currentSelection).find("option").each(function() {
							if($(this).html() === thisSelected.html()) {
								thisSelected.remove();
							}
						});
					});
					GipAddSelectedItems(master);
					// Set master.data to the newly allowable values
					master.data = GipGetGroupData(newMultiLookupPickerdata);

					// Trigger a dblclick so that the child will be cascaded if it is a multiselect.
					childSelect.Obj.trigger("dblclick");

					break;
				default:
					break;
			}
		}
	});
	// If present, call completefunc when all else is done
	if(opt.completefunc !== null) {
		opt.completefunc();
	}
} // End cascadeDropdown

	// Find a dropdown (or multi-select) in the DOM. Returns the dropdown onject and its type:
	// S = Simple (select);C = Compound (input + select hybrid);M = Multi-select (select hybrid)
	function dropdownCtl(colName) {
		// Simple
		if((this.Obj = $("select[Title='" + colName + "']")).html() !== null) {
			this.Type = "S";
		// Compound
		} else if((this.Obj = $("input[Title='" + colName + "']")).html() !== null) {
			this.Type = "C";
		// Multi-select: This will find the multi-select column control in English and most other languages sites where the Title looks like 'Column Name possible values'
		} else if((this.Obj = $("select[ID$='SelectCandidate'][Title^='" + colName + " ']")).html() !== null) {
			this.Type = "M";
		// Multi-select: This will find the multi-select column control on a Russian site (and perhaps others) where the Title looks like '????????? ????????: Column Name'
		} else if((this.Obj = $("select[ID$='SelectCandidate'][Title$=': " + colName + "']")).html() !== null) {
			this.Type = "M";
		// Multi-select: This will find the multi-select column control on a German site (and perhaps others) where the Title looks like 'Mögliche Werte für &quot;Tops&quot;.'
		} else if((this.Obj = $("select[ID$='SelectCandidate'][Title$='\"" + colName + "\".']")).html() !== null) {
			this.Type = "M";
		} else {
			this.Type = null;
		}
	} // End of function dropdownCtl

	// Escape column values
	function escapeColumnValue(s) {
		if(typeof s == "string") {
			return s.replace(/&(?![a-zA-Z]{1,8};)/g, "&amp;");
		} else {
			return s;
		}
	}
	
May 8, 2012 at 7:18 AM

BTW:

As you will see, if you compare SPCascadeDropdownsCUSTOM with SPCascadeDropdowns, I didn't change a lot actually. I just introduced two extra fields and added some code to add to the CAML query.

So most of the code I included already exists, but I posted the complete code for clarity.

Regards,
Ernst Wolthaus

May 14, 2012 at 7:26 AM

@Chris (yelokahon),

If you would like 4 parentcolumns:

Look for the variables containing 'parentExtra' and triple the related code so for example you will have these parameters:

  • relationshipListParentExtraColumn1
  • parentExtraColumn1
  • relationshipListParentExtraColumn2
  • parentExtraColumn2
  • relationshipListParentExtraColumn3
  • parentExtraColumn3

Copy and triple the code looking for the value in the 4 parent dropdowns.

Finally, extend the CAML query that is build, based on these extra parameters.

It shouldn't be that hard...

Good luck!

 

Jun 8, 2012 at 5:49 PM

I had the some problem and got around it by simply designating a function that would build the CAMLQuery dynamically.  You can see the functionality here.