Last active
March 8, 2016 06:02
-
-
Save sharepointland/97770f659887c538f1a3 to your computer and use it in GitHub Desktop.
Add Cascading Drop-downs To Any List or Library
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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