Quantcast
Viewing all articles
Browse latest Browse all 6517

Edited Issue: SPCascadingDropdowns() - Issue with PrependId [10066]

From http://spservices.codeplex.com/discussions/316604

I'm sorry it has taken me a while to get back to this thread, but I've done some more testing and researching.

I am provisioning my Lookup fields via field definitions in Visual Studio. I create my lookup fields similar to this:
<Field ID="{F9E3BD77-AEC6-4CF2-A231-868C64120CFD}"
Name="My_LookupField"
DisplayName="My Lookup Field"
Group="Columns"
Type="LookupMulti"
Mult="TRUE"
List="Lists/MyList"
ShowField="Title"
PrependId="TRUE"
Required="FALSE"
DisplaceOnUpgrade="TRUE"
SourceID="{655b3843-a6eb-4355-85bf-722e11c14c59}" />

Notice the PrependId attribute in my definition. This causes the Candidate options to look like this: 1 - Option1, 2 - Option2, etc. In the cascadeDropdown function, you are rebuilding the master data:

// ows_Title does not contain the Id like the Candidate and SelectResult fields do by default.
// Instead of 1 - OptionA, ows_Title returns just OptionA
var thisValue = $(this).attr("ows_" + opt.relationshipListChildColumn);

// Lets say the thisValue = "OptionA"
var thisValue = $(this).attr("ows_" + opt.relationshipListChildColumn);
// It skips the split() block
if(thisValue !== undefined && thisValue.indexOf(";#") > 0) {
var splitValue = thisValue.split(";#");
thisOptionId = splitValue[0];
thisOptionValue = splitValue[1];
}
else {
// thisOptionId will now be 1
thisOptionId = $(this).attr("ows_ID");
// thisOptionValue will now be OptionA
thisOptionValue = thisValue;
}

// A little further on down
case "M":
// <option value='1'>OptionA</option>
childSelect.Obj.append("<option value='" + thisOptionId + "'>" + thisOptionValue + "</option>");
// 1|tOptionA|t |t |t
newMultiLookupPickerdata += thisOptionId + "|t" + thisOptionValue + "|t |t |t";
break;

By doing so, this is creating a different option and data string. The original option in the Candidate was <option value="1">1 - OptionA</option>. However, we now end up with a new option; <option value="1">OptionA</option> in our childSelect.Obj options. Now, a little further on down:

case "M":
// Find the important bits of the multi-select
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 = "";

MultiLookupPickerdata.attr("value", newMultiLookupPickerdata);
// Clear any prior selections that are no longer valid
$(currentSelection).find("option").each(function() {
var thisSelected = $(this);
// I changed this to use .val() instead of .html()
var thisValue = $(this).val();
$(this).attr("selected", "selected");
// I changed this to .find().each() instead of a contains
$(childSelect.Obj).find("option").each(function() {
// I changed this to use .val() instead of .html()
if($(this).val() == thisValue) {
thisSelected.removeAttr("selected");
}
});

// Removed the following code because:
// currentSelection.option.html() is actually Value - Text (Ex: 1 - OptionA and 2 - OptionB)
// childSelect.Obj.option.html() is actually Text (Ex: OptionA and OptionB)
// If the options in childSelect are [OptionA, OptionB, OptionC] and currentSelection are [1 - OptionA, 2 - OptionB, 3 - OptionC],
// childSelect will never find an option that contains the currentSelection option

//$(childSelect.Obj).find("option:contains('" + thisValue + "')").each(function() {
// if($(this).html() === thisValue) {
// thisSelected.removeAttr("selected");
// }
//});
});

// Set master.data to the newly allowable values
master.data = GipGetGroupData(newMultiLookupPickerdata);

// GipRemoveSelectedItems() will take any options in the _SearchResult field (Selected Values) that are marked as "selected"
// and move them to the _Candidate field (Possible Values)
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() {
// I changed this to use the values instead of the html()
if($(this).val() == thisSelected.val()) {
thisSelected.remove();
}
});

// Removed the following code because:
// currentSelection.option.html() is actually Value - Text (Ex: 1 - OptionA and 2 - OptionB)
// childSelect.Obj.option.html() is actually Text (Ex: OptionA and OptionB)
// If the options in childSelect are [OptionA, OptionB, OptionC] and currentSelection are [1 - OptionA, 2 - OptionB, 3 - OptionC],
// childSelect will never match an option in the currentSelection options

//$(currentSelection).find("option").each(function() {
// if($(this).html() === thisSelected.html()) {
// thisSelected.remove();
// }
//});
});

// GipAddSelectedItems() will take any options in the _Candidate field (Possible Values) that are marked as "selected"
// and move them to the _SearchResult field (Selected Values)
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;



If you look at the commented out code (the original) you will see that I changed it to use .val() instead of .html() and I removed the .find("option:contains..") to .find("option").each(). By changing this code I can now update, save, and reload the multiselect boxes without loosing any data at all.

I also went back and turned PrependId to false and retested. Sure enough, it works fine. So I got to thinking about that and I updated the code to support the PrependId option. Here it is:




// In $.fn.SPServices.SPCascadeDropdowns

// 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;
childColumnStatic = $(this).attr("StaticName");
// Jeremy Rose - 4/27/2012: Add this new variable to hold the PrependId value
childColumnPrependId = $(this).attr("PrependId");
// Stop looking; we're done
return false;
});
});
}
});

// Save data about each child column on the parent
// Jeremy Rose - 4/27/2012: Add Prepend variable to column data
var childColumn = {opt: opt, childSelect: childSelect, childColumnStatic: childColumnStatic, childColumnRequired: childColumnRequired, childColumnPrependId: childColumnPrependId};

// In function cascadeDropdown

function cascadeDropdown(parentColumn, parentSelect) {
var choices = "";
var parentSelectSelected;
var childSelectSelected = null;
var master;
var MultiLookupPickerdata;
var newMultiLookupPickerdata;
var numChildOptions;
var firstChildOptionId;
var firstChildOptionValue;

// Filter each child column
var childColumns = parentSelect.Obj.data("SPCascadeDropdownsChildColumns");
$(childColumns).each(function() {

// Break out the data objects for this child column
var opt = this.opt;
var childSelect = this.childSelect;
var childColumnStatic = this.childColumnStatic;
var childColumnRequired = this.childColumnRequired;
// Jeremy Rose - 4/27/2012: Get the PrependId variable here
var childColumnPrependId = (this.childColumnPrependId != undefined) ? this.childColumnPrependId : "FALSE";

// Get the parent column selection(s)
parentSelectSelected = getDropdownSelected(parentSelect, opt.matchOnId);

// 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.
if(parentSelect.Obj.data("SPCascadeDropdown_Selected_" + childColumnStatic) === parentSelectSelected.join(";#")) {
return;
}
parentSelect.Obj.data("SPCascadeDropdown_Selected_" + childColumnStatic, parentSelectSelected.join(";#"));

// Get the current child column selection(s)
childSelectSelected = getDropdownSelected(childSelect, true);

// 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><And>";
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 += "<Eq><FieldRef Name='" + opt.relationshipListParentColumn + "'/><Value Type='Text'></Value></Eq>";
} else if(parentSelectSelected.length === 1) {
// Only one value is selected
camlQuery += "<Eq><FieldRef Name='" + opt.relationshipListParentColumn +
(opt.matchOnId ? "' LookupId='True'/><Value Type='Integer'

Viewing all articles
Browse latest Browse all 6517

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>