Friday 9 March 2018

Multi Level Cascading Dropdown for Sharepoint 2013 and SharePoint Online

Hello Every one. In this blog we are going to implement the multi level cascade drop down in SharePoint new and edit forms with the help of Rest Api.

We no need to create multiple list to store the source data. We can keep all the hierarchy of the data in a single list as shown below.


We have a master list in which we are storing the Country, State, City and District as a lookup column from the above list.


Now add the following code in the default new form and edit form.




<script type="text/javascript" src="jquery-1.12.0.min.js"></script>
<script type="text/javascript" src="cascadeDropdownPlugin.js"></script>
<script type="text/javascript">

 jQuery(document).ready(function() {

jQuery.fn.cascadeDropdownPlugin.Methods._init({
          parentListTitle: "Custom Cascade",
           sourceFields: "Title,State,City,District",
           destinationFields: ["Country lookup", "State lookup", "City lookup", "District lookup Required Field"]
         }); 
});

</script> 

In the above code


jQuery.fn.cascadeDropdownPlugin.Methods._init({
   parentListTitle: Source List title
    sourceFields: <<Internal Name>>. These are the columns which we are going to lookup in the master list. Basically these are the columns that is in the Source List. This field should be in comma separated,
    destinationFields: <<Display Name>>.These are the fields that is in the master list. This should be in an array format. 
}); 

If  there is any required field then we have to append "Required Field" in the end of the display name. For example "District lookup" is a column in the master list. If we made the field required then the name should became "District lookup Required Field" while passing into the function.

With this code we can use 'n' number of cascade drop-downs.

The source field sequence and the destination field sequence should be in the same order. For example

The destinationFields should maintain the same order as in the sourceFields.

The result will be looking like the below image.




Please find the code below for the cascadeDropdownPlugin.js


(function ($) {
jQuery.fn.cascadeDropdownPlugin = jQuery.fn.cascadeDropdownPlugin || {};
var sourceData = [];
var input = [];

jQuery.fn.cascadeDropdownPlugin.ServiceCalls = {
getSourceFieldsValues: function (options) {
if (options.parentListTitle == undefined || options.sourceFields == undefined || options.destinationFields == undefined)
alert("Message from cascade plugin : The Input JSON is not in correct format");
else {
input = options;
jQuery.ajax({
url: _spPageContextInfo.webAbsoluteUrl + "/_api/web/lists/GetByTitle('" + options.parentListTitle + "')/items?$select=Id," + options.sourceFields,
method: "GET",
headers: { "Accept": "application/json; odata=verbose" },
success: function (data) {
if (data.d.results != undefined) {
sourceData = data.d.results;
jQuery.fn.cascadeDropdownPlugin.logic.removeOptions(options.destinationFields);
jQuery.fn.cascadeDropdownPlugin.logic.addCustomAttribute(options.destinationFields);
jQuery.fn.cascadeDropdownPlugin.logic.addOptions(sourceData, options);
jQuery.fn.cascadeDropdownPlugin.logic.bindChangeEvent(options.destinationFields);
}
},
error: function (msg) {
alert("Message from cascade plugin : " + JSON.parse(msg.responseText).error.message.value);
}
});
}
}
}

jQuery.fn.cascadeDropdownPlugin.logic = {
addOptions: function (sourceData, options) {
var template = "<option value='[val]'>[display]</option>";
var sourceFields = options.sourceFields.split(',');
var firstElement = jQuery("select[title='" + options.destinationFields[0] + "']");

var lookup = {};
var items = sourceData;
var temp = [];
for (var item, i = 0; item = items[i++];) {
var name = item[sourceFields[0]]

if (!(name in lookup)) {
lookup[name] = 1;
jQuery(template.replace('[val]', item.Id).replace('[display]', name)).appendTo(firstElement);
}
}
},

removeOptions: function (fields) {
var destinationFields = fields;
for (var i = 0; i < destinationFields.length; i++) {
jQuery("select[title='" + destinationFields[i] + "'] option").remove();
jQuery("<option value='0'>None</option>").appendTo(jQuery("select[title='" + destinationFields[i] + "']"));
}
},

addCustomAttribute: function (fields) {
var destinationFields = fields;
for (var i = 0; i < destinationFields.length; i++) {
jQuery("select[title='" + destinationFields[i] + "']").attr('data-cascade', i);
}
},

changeEvent: function (e) {
var selectedText = e.target.selectedOptions[0].text;
var selectedValue = e.target.selectedOptions[0].value;
var ctrlNo = Number(e.target.getAttribute("data-cascade"));
var ctrls = input.destinationFields;
if (ctrls.length - 1 == ctrlNo) {
for (var i = 0; i < ctrls.length - 1; i++) {
jQuery("select[title='" + ctrls[i] + "'] option:selected").val(selectedValue);
}
}
else {
var template = "<option value='[val]'>[display]</option>";
var sourceFields = input.sourceFields.split(',');
var nthElement = jQuery("select[title='" + ctrls[ctrlNo + 1] + "']");

for (var k = ctrlNo + 1; k < ctrls.length; k++) {
jQuery("select[title='" + ctrls[k] + "'] option").remove();
jQuery("<option value='0'>None</option>").appendTo(jQuery("select[title='" + ctrls[k] + "']"));
}

var lookup = {};
var items = sourceData;
var temp = [];
for (var item, i = 0; item = items[i++];) {
if (item[sourceFields[ctrlNo]] == selectedText) {
var name = item[sourceFields[ctrlNo + 1]]
if (!(name in lookup)) {
if (name != undefined) {
lookup[name] = 1;
jQuery(template.replace('[val]', item.Id).replace('[display]', name)).appendTo(nthElement);
}
else
break;
}
}
}
}

},

bindChangeEvent: function (fields) {
var destinationFields = fields;
for (var i = 0; i < destinationFields.length; i++) {
jQuery("select[title='" + destinationFields[i] + "']").change(this.changeEvent);
}
}
}

jQuery.fn.cascadeDropdownPlugin.Methods = {
_init: function (options) {
jQuery.fn.cascadeDropdownPlugin.ServiceCalls.getSourceFieldsValues(options);
}
}
})(jQuery);



Friday 31 July 2015

Angular JS-Multi select dropdownlist

Multi select Drop down list using AngularJS and Bootstrap



Code

Html

<div ng-controller="multiselectddlController">
    <div style="font-weight: bold;">Get Selected Country</div>
    <div data-ng-repeat="country in SelectedCountries">
        <ul>
            <li>{{country.name}}</li>
        </ul>
    </div>
    <multiselect-dropdown model=" SelectedCountries " options="MasterCountries "></multiselect-dropdown>
</div>

Module

var multiddl = angular.module('multiddl', []);

Directive


multiddl.directive('multiselectDropdown', function () {
    return {
        restrict: 'E',
        scope: {
            model: '=',
            options: '=',
        },
        template:
            "<div class='btn-group' data-ng-class='{open: open}' style='width: 200px;'>" +
            "<button class='btn btn-small' style='width: 160px;'>---Select---</button>" +
            "<button class='btn btn-small dropdown-toggle' data-ng-click='openDropdown()' style='width: 40px;' ><span class='caret'></span></button>" +
            "<ul class='dropdown-menu' aria-labelledby='dropdownMenu' style='position: relative;'>" +
            "<li style='cursor:pointer;' data-ng-repeat='option in options'><a data-ng-click='toggleSelectItem(option)'><span data-ng-class='getClassName(option)' aria-hidden='true'></span> {{option.name}}</a></li>" +
            "</ul>" +
            "</div>",

        controller: function ($scope) {

            $scope.openDropdown = function () {

                $scope.open = !$scope.open;

            };

            $scope.selectAll = function () {

                $scope.model = [];

                angular.forEach($scope.options, function (item, index) {

                    $scope.model.push(item);

                });

            };

            $scope.deselectAll = function () {

                $scope.model = [];

            };

            $scope.toggleSelectItem = function (option) {

                var intIndex = -1;

                angular.forEach($scope.model, function (item, index) {

                    if (item.id == option.id) {

                        intIndex = index;

                    }

                });

                if (intIndex >= 0) {

                    $scope.model.splice(intIndex, 1);

                } else {

                    $scope.model.push(option);

                }

            };

            $scope.getClassName = function (option) {

                var varClassName = 'glyphicon glyphicon-remove-circle';

                angular.forEach($scope.model, function (item, index) {

                    if (item.id == option.id) {

                        varClassName = 'glyphicon glyphicon-ok-circle';

                    }

                });

                return (varClassName);

            };

        }
    }

});

Controller:

multiddl.controller("multiselectddlController", function ($scope) {
    $scope.SelectedCountries = [{
        "id": 1,
            "name": "India"
    }, {
        "id": 3,
            "name": "Japan"
    }, {
        "id": 5,
            "name": "Germany"
    }];
    $scope.MasterCountries = [{
        "id": 1,
            "name": "India"
    }, {
        "id": 2,
            "name": "America"
    }, {
        "id": 3,
            "name": "Japan"
    }, {
        "id": 4,
            "name": "China"
    }, {
        "id": 5,
            "name": "Germany"
    }]
});


Explanation

  •  In this example I am using angular js directive to achieve the functionality of multi select drop down list. Here I am using the directive as an element.  This you can achieve by using  "restrict: 'E'". If you use "A" the directive will act as an attribute.
  • You can get the multi select drop down by passing $scope to model and option in the directive
  • Pass selected $scope to model and pass master $scope to option
  • The model and option $scope structure should be as: {"id":1,"name":'example'}
  • Here bootstrap is used to get the style and glyphicons

Demo