Skip to content

Instantly share code, notes, and snippets.

@sharepointland
Last active March 8, 2016 06:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sharepointland/97770f659887c538f1a3 to your computer and use it in GitHub Desktop.
Save sharepointland/97770f659887c538f1a3 to your computer and use it in GitHub Desktop.
Add Cascading Drop-downs To Any List or Library
//http://jedcurl.blogspot.com/2016/03/add-cascading-drop-downs-to-any-list-or.html
(function () {
//Configurable Values:
var restUrl="/_api/web/lists/GetByTitle('Cascading Choices')/items";//URL for the Source Options list containing all cascading drop-down options
var noChoicesText = "[No options available]";
var maxSourceItems = "2000";
var Level1InternalName = "Continent";//Cascading Drop-down list's level 1 column name, also update line 19
var Level2InternalName = "Country";//Cascading Drop-down list's level 2 column name, also update line 23
var Level3InternalName = "State";//Cascading Drop-down list's level 3 column name, also update line 27, set both to "" if only 2 cascading drop-downs
var Level4InternalName = "City";//Cascading Drop-down list's level 4 column name, also update line 31, set both to "" if only 3 cascading drop-downs
var Level5InternalName = "Neighborhood";//Cascading Drop-down list's level 5 column name, also update line 31, set both to "" if only 3 cascading drop-downs
var Level1Source = "Level1";//internal name of the column containing the level 1 choices in the Source Options list
var Level2Source = "Level2";//internal name of the column containing the level 2 choices in the Source Options list
var Level3Source = "Level3";//internal name of the column containing the level 3 choices in the Source Options list, set to "" if only 2 cascading drop-downs
var Level4Source = "Level4";//internal name of the column containing the level 4 choices in the Source Options list, set to "" if only 3 cascading drop-downs
var Level5Source = "Level5";//internal name of the column containing the level 5 choices in the Source Options list, set to "" if only 3 cascading drop-downs
// Create object that have the context information about the field that we want to change it's output render
var cascadingFieldContext = {};
cascadingFieldContext.Templates = {};
cascadingFieldContext.Templates.Fields = {
// Apply the new rendering for all fields on New and Edit forms
"Continent": {
"NewForm": renderLevel1Field,
"EditForm": renderLevel1Field
},
"Country": {
"NewForm": renderLevel2Field,
"EditForm": renderLevel2Field
},
"State": {
"NewForm": renderLevel3Field,
"EditForm": renderLevel3Field
},
"City": {
"NewForm": renderLevel4Field,
"EditForm": renderLevel4Field
},
"Neighborhood": {
"NewForm": renderLevel5Field,
"EditForm": renderLevel5Field
}
};
SPClientTemplates.TemplateManager.RegisterTemplateOverrides(cascadingFieldContext);
//Always start by populating the top drop-down in the cascading hierarchy
function renderLevel1Field(ctx) {
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
var fieldInternalName = ctx.CurrentFieldSchema.Name;
var controlId = "ddl"+Level1InternalName;
ctx.FormContext.registerInitCallback(fieldInternalName, function () {
$addHandler($get(controlId), "change", function(e) {
ctx.FormContext.updateControlValue(fieldInternalName, $("#"+controlId).val());
$("#ddl"+Level2InternalName).trigger("clear");
getDDLChoices(populateLevel2Choices);
});
getDDLChoices(populateLevel1Choices);
});
var validators = new SPClientForms.ClientValidation.ValidatorSet();
validators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator());
formCtx.registerValidationErrorCallback(formCtx.fieldName,
function (errorResult) {
SPFormControl_AppendValidationErrorMessage(controlId+"Validator", errorResult);
}
);
formCtx.registerClientValidator(formCtx.fieldName, validators);
// Register a callback just before submit.
formCtx.registerGetValueCallback(formCtx.fieldName, function () {
return $("#"+controlId).val();
});
if(formCtx.fieldValue != ""){
return '<select name="'+Level1InternalName+'" id="'+controlId+'"><option value="'+ formCtx.fieldValue +'" Selected>'+ formCtx.fieldValue +'</option></select><div id="'+controlId+'Validator"></div>';
}else
return '<select name="'+Level1InternalName+'" id="'+controlId+'"><option value=""></option></select><div id="'+controlId+'Validator"></div>';
}
function renderLevel2Field(ctx) {
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
var fieldInternalName = ctx.CurrentFieldSchema.Name;
var controlId = "ddl"+Level2InternalName;
ctx.FormContext.registerInitCallback(fieldInternalName, function () {
$addHandler($get(controlId), "change", function(e) {
ctx.FormContext.updateControlValue(fieldInternalName, $("#"+controlId).val());
$("#ddl"+Level3InternalName).trigger("clear");
getDDLChoices(populateLevel3Choices);
});
$("#"+controlId).on("clear", function(e) {
$("#ddl"+Level3InternalName).trigger("clear");
$("#"+controlId).empty();
$("#"+controlId).prop("disabled", true);
$("#"+controlId).prepend("<option value='' disabled selected>"+noChoicesText+"</option>");
$("#"+controlId).val('');
});
getDDLChoices(populateLevel2Choices);
});
var validators = new SPClientForms.ClientValidation.ValidatorSet();
validators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator());
formCtx.registerValidationErrorCallback(formCtx.fieldName,
function (errorResult) {
SPFormControl_AppendValidationErrorMessage(controlId+"Validator", errorResult);
}
);
formCtx.registerClientValidator(formCtx.fieldName, validators);
// Register a callback just before submit.
formCtx.registerGetValueCallback(formCtx.fieldName, function () {
return $("#"+controlId).val();
});
if(formCtx.fieldValue != ""){
return '<select name="'+Level2InternalName+'" id="'+controlId+'"><option value="'+ formCtx.fieldValue +'" Selected>'+ formCtx.fieldValue +'</option></select><div id="'+controlId+'Validator"></div>';
}else
return '<select name="'+Level2InternalName+'" id="'+controlId+'"><option value=""></option></select><div id="'+controlId+'Validator"></div>';
}
function renderLevel3Field(ctx) {
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
var fieldInternalName = ctx.CurrentFieldSchema.Name;
var controlId = "ddl"+Level3InternalName;//fieldInternalName + "_control";
ctx.FormContext.registerInitCallback(fieldInternalName, function () {
$addHandler($get(controlId), "change", function(e) {
ctx.FormContext.updateControlValue(fieldInternalName, $("#"+controlId).val());
$("#ddl"+Level4InternalName).trigger("clear");
getDDLChoices(populateLevel4Choices);
});
$("#"+controlId).on("clear", function(e) {
$("#ddl"+Level4InternalName).trigger("clear");
$("#"+controlId).empty();
$("#"+controlId).prop( "disabled", true);
$("#"+controlId).prepend("<option value='' disabled selected>"+noChoicesText+"</option>");
$("#"+controlId).val('');
});
getDDLChoices(populateLevel3Choices);
});
var validators = new SPClientForms.ClientValidation.ValidatorSet();
validators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator());
formCtx.registerValidationErrorCallback(formCtx.fieldName,
function (errorResult) {
SPFormControl_AppendValidationErrorMessage(controlId+"Validator", errorResult);
}
);
formCtx.registerClientValidator(formCtx.fieldName, validators);
// Register a callback just before submit.
formCtx.registerGetValueCallback(formCtx.fieldName, function () {
return $("#"+controlId).val();
});
if(formCtx.fieldValue != ""){
return '<select name="'+Level3InternalName+'" id="'+controlId+'"><option value="'+ formCtx.fieldValue +'" Selected>'+ formCtx.fieldValue +'</option></select><div id="'+controlId+'Validator"></div>';
}else
return '<select name="'+Level3InternalName+'" id="'+controlId+'"><option value=""></option></select><div id="'+controlId+'Validator"></div>';
}
function renderLevel4Field(ctx) {
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
var fieldInternalName = ctx.CurrentFieldSchema.Name;
var controlId = "ddl"+Level4InternalName;//fieldInternalName + "_control";
ctx.FormContext.registerInitCallback(fieldInternalName, function () {
$addHandler($get(controlId), "change", function(e) {
ctx.FormContext.updateControlValue(fieldInternalName, $("#"+controlId).val());
$("#ddl"+Level5InternalName).trigger("clear");
getDDLChoices(populateLevel5Choices);
});
$("#"+controlId).on("clear", function(e) {
$("#ddl"+Level5InternalName).trigger("clear");
$("#"+controlId).empty();
$("#"+controlId).prop( "disabled", true);
$("#"+controlId).prepend("<option value='' disabled selected>"+noChoicesText+"</option>");
$("#"+controlId).val('');
});
getDDLChoices(populateLevel4Choices);
});
var validators = new SPClientForms.ClientValidation.ValidatorSet();
validators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator());
formCtx.registerValidationErrorCallback(formCtx.fieldName,
function (errorResult) {
SPFormControl_AppendValidationErrorMessage(controlId+"Validator", errorResult);
}
);
formCtx.registerClientValidator(formCtx.fieldName, validators);
// Register a callback just before submit.
formCtx.registerGetValueCallback(formCtx.fieldName, function () {
return $("#"+controlId).val();
});
if(formCtx.fieldValue != ""){
return '<select name="'+Level4InternalName+'" id="'+controlId+'"><option value="'+ formCtx.fieldValue +'" Selected>'+ formCtx.fieldValue +'</option></select><div id="'+controlId+'Validator"></div>';
}else
return '<select name="'+Level4InternalName+'" id="'+controlId+'"><option value=""></option></select><div id="'+controlId+'Validator"></div>';
}
function renderLevel5Field(ctx) {
var formCtx = SPClientTemplates.Utility.GetFormContextForCurrentField(ctx);
var fieldInternalName = ctx.CurrentFieldSchema.Name;
var controlId = "ddl"+Level5InternalName;
ctx.FormContext.registerInitCallback(fieldInternalName, function () {
$addHandler($get(controlId), "change", function(e) {
ctx.FormContext.updateControlValue(fieldInternalName, $("#"+controlId).val());
});
$("#"+controlId).on("clear", function(e) {
$("#"+controlId).empty();
$("#"+controlId).prop("disabled", true);
$("#"+controlId).prepend("<option value='' disabled selected>"+noChoicesText+"</option>");
$("#"+controlId).val('');
});
getDDLChoices(populateLevel5Choices);
});
var validators = new SPClientForms.ClientValidation.ValidatorSet();
validators.RegisterValidator(new SPClientForms.ClientValidation.RequiredValidator());
formCtx.registerValidationErrorCallback(formCtx.fieldName,
function (errorResult) {
SPFormControl_AppendValidationErrorMessage(controlId+"Validator", errorResult);
}
);
formCtx.registerClientValidator(formCtx.fieldName, validators);
// Register a callback just before submit.
formCtx.registerGetValueCallback(formCtx.fieldName, function () {
return $("#"+controlId).val();
});
if(formCtx.fieldValue != ""){
return '<select name="'+Level5InternalName+'" id="'+controlId+'"><option value="'+ formCtx.fieldValue +'" Selected>'+ formCtx.fieldValue +'</option></select><div id="'+controlId+'Validator"></div>';
}else
return '<select name="'+Level5InternalName+'" id="'+controlId+'"><option value=""></option></select><div id="'+controlId+'Validator"></div>';
}
function getDDLChoices(populateFunction){
var field="";
var modifiedRestUrl = restUrl;
switch(populateFunction)
{
case populateLevel1Choices:
console.log("Level 1 Choices");
modifiedRestUrl += "?$select="+Level1Source+"&$orderby="+Level1Source+" asc&$top="+maxSourceItems;
field=Level1Source;
break;
case populateLevel2Choices:
console.log("Level 2 Choices");
modifiedRestUrl += "?$select="+Level2Source+"&$filter="+Level1Source+" eq '"+$("#ddl"+Level1InternalName).val()+"'&distinct=true&$orderby="+Level2Source+" asc&$top="+maxSourceItems;
field=Level2Source;
break;
case populateLevel3Choices:
if(Level3InternalName == "" || Level3Source == "") {return {};}
console.log("Level 3 Choices");
modifiedRestUrl += "?$select="+Level3Source+"&$filter="+Level1Source+" eq '"+$("#ddl"+Level1InternalName).val()+"' and "+Level2Source+" eq '"+$("#ddl"+Level2InternalName).val()+"'&$orderby="+Level3Source+" asc&$top="+maxSourceItems;
field=Level3Source;
break;
case populateLevel4Choices:
if(Level4InternalName == "" || Level4Source == "") {return {};}
console.log("Level 4 Choices");
modifiedRestUrl += "?$select="+Level4Source+"&$filter="+Level1Source+" eq '"+$("#ddl"+Level1InternalName).val()+"' and "+Level2Source+" eq '"+$("#ddl"+Level2InternalName).val()+"' and "+Level3Source+" eq '"+$("#ddl"+Level3InternalName).val()+"'&$orderby="+Level4Source+" asc&$top="+maxSourceItems;
field=Level4Source;
break;
case populateLevel5Choices:
if(Level5InternalName == "" || Level5Source == "") {return {};}
console.log("Level 5 Choices");
modifiedRestUrl += "?$select="+Level5Source+"&$filter="+Level1Source+" eq '"+$("#ddl"+Level1InternalName).val()+"' and "+Level2Source+" eq '"+$("#ddl"+Level2InternalName).val()+"' and "+Level3Source+" eq '"+$("#ddl"+Level3InternalName).val()+"' and "+Level4Source+" eq '"+$("#ddl"+Level4InternalName).val()+"'&$orderby="+Level5Source+" asc&$top="+maxSourceItems;
field=Level5Source;
break;
default:
modifiedRestUrl=modifiedRestUrl;
}
console.log(modifiedRestUrl);
return $.ajax({
url: modifiedRestUrl,
type: "GET",
headers: {
"accept": "application/json;odata=verbose"
},
success: function(result){
if (result && result.d && result.d.results) {
var resultDeduped = [];
$.each(result.d.results, function(index, item) {
//removes duplicates and null/empty items
if (($.inArray(item[field], resultDeduped)==-1) && (item[field] !== null)) {
resultDeduped.push(item[field]);
}
});
populateFunction(resultDeduped);
}
},
error: function(result){
console.log("Error: " + modifiedRestUrl);
console.log(result);
}
});
}
function populateLevel1Choices(result) {
var currentVal = $("#ddl"+Level1InternalName).val();
console.log("Current Level 1: " + currentVal);
$("#ddl"+Level1InternalName).empty();
for (var i = 0; i < result.length; i++)
{
console.log(result[i]);
//Add this option to the select element and mark it selected if it matches the currentVal
$("#ddl"+Level1InternalName).append("<option value='" + result[i] + ((result[i]==currentVal) ? "' Selected":"'") +">" + result[i] + "</option");
}
if(currentVal == $("#ddl"+Level1InternalName).val())
{
getDDLChoices(populateLevel2Choices);
}else
{
//Adds empty option to current field when item doesn't already have value
$("#ddl"+Level1InternalName).prepend("<option Selected='Selected' value=''></option");
$("#ddl"+Level1InternalName).val('');
}
}
function populateLevel2Choices(result) {
var currentVal = $("#ddl"+Level2InternalName).val();
console.log("Current Level 2: " + currentVal);
$("#ddl"+Level2InternalName).empty();
$("#ddl"+Level2InternalName).prop( "disabled", false);
if(result.length > 0){
for (var i = 0; i < result.length; i++)
{
console.log(result[i]);
$("#ddl"+Level2InternalName).append("<option value='" + result[i] + ((result[i]==currentVal) ? "' Selected":"'") +">" + result[i] + "</option");
}
if(currentVal == $("#ddl"+Level2InternalName).val())
{
getDDLChoices(populateLevel3Choices);
}else
{
//Adds empty but descriptive option to current field
$("#ddl"+Level2InternalName).prepend("<option Selected='Selected' value=''></option");
$("#ddl"+Level2InternalName).val('');
}
}else
{
$("#ddl"+Level2InternalName).append("<option value='' disabled selected>"+noChoicesText+"</option>");
$("#ddl"+Level2InternalName).prop("disabled", true);
}
}
function populateLevel3Choices(result) {
var currentVal = $("#ddl"+Level3InternalName).val();
console.log("Current Level 3: " + currentVal);
$("#ddl"+Level3InternalName).empty();
$("#ddl"+Level3InternalName).prop( "disabled", false);
if(result.length > 0){
for (var i = 0; i < result.length; i++)
{
console.log(result[i]);
$("#ddl"+Level3InternalName).append("<option value='" + result[i] + ((result[i]==currentVal) ? "' Selected":"'") +">" + result[i] + "</option");
}
if(currentVal == $("#ddl"+Level3InternalName).val())
{
getDDLChoices(populateLevel4Choices);
}else
{
//Adds empty but descriptive option to current field
$("#ddl"+Level3InternalName).prepend("<option Selected='Selected' value=''></option");
$("#ddl"+Level3InternalName).val('');
}
}else
{
$("#ddl"+Level3InternalName).append("<option value='' disabled selected>"+noChoicesText+"</option>");
$("#ddl"+Level3InternalName).prop("disabled", true);
}
}
function populateLevel4Choices(result) {
var currentVal = $("#ddl"+Level4InternalName).val();
console.log("Current Level 4: " + currentVal);
$("#ddl"+Level4InternalName).empty();
$("#ddl"+Level4InternalName).prop("disabled", false);
if(result.length > 0){
for (var i = 0; i < result.length; i++)
{
console.log(result[i]);
$("#ddl"+Level4InternalName).append("<option value='" + result[i] + ((result[i]==currentVal) ? "' Selected":"'") +">" + result[i] + "</option");
}
if(currentVal == $("#ddl"+Level4InternalName).val())
{
getDDLChoices(populateLevel5Choices);
}else
{
//Adds empty but descriptive option to current field
$("#ddl"+Level4InternalName).prepend("<option Selected='Selected' value=''></option");
$("#ddl"+Level4InternalName).val('');
}
}else
{
$("#ddl"+Level4InternalName).append("<option value='' disabled selected>"+noChoicesText+"</option>");
$("#ddl"+Level4InternalName).prop("disabled", true);
}
}
function populateLevel5Choices(result) {
var currentVal = $("#ddl"+Level5InternalName).val();
console.log("Current Level 5: " + currentVal);
$("#ddl"+Level5InternalName).empty();
$("#ddl"+Level5InternalName).prop("disabled", false);
if(result.length > 0){
for (var i = 0; i < result.length; i++)
{
console.log(result[i]);
$("#ddl"+Level5InternalName).append("<option value='" + result[i] + ((result[i]==currentVal) ? "' Selected":"'") +">" + result[i] + "</option");
}
if(currentVal == $("#ddl"+Level5InternalName).val())
{
}else
{
//Adds empty but descriptive option to current field
$("#ddl"+Level5InternalName).prepend("<option Selected='Selected' value=''></option");
$("#ddl"+Level5InternalName).val('');
}
}else
{
$("#ddl"+Level5InternalName).append("<option value='' disabled selected>"+noChoicesText+"</option>");
$("#ddl"+Level5InternalName).prop("disabled", true);
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment