Introduction
This article implements the Treeview with multiselect option like items inside server-side binding and searches within the tree. This is an enhancement to the previous article [https://www.codeproject.com/Tips/862784/Treeview-Dropdown-With-Search] after I received the request to enable MultiSelect
functionality inside this treeview
.
Background
As this is an enhancement to the previous article https://www.codeproject.com/Tips/862784/Treeview-Dropdown-With-Search, please visit the article to know the basics. Although you can still understand it without going through the previous one as it also contains sufficient information.
Having knowledge of HTML and Kendo is appreciated.
Note: For binding the dropdown
with server side, having knowledge of WCF/MVC/WebMethod
is a prerequisite.
Using the Code
What we will have in the end: We will have a treeview
where on selecting any node/nodes, it will list in multiselect
and again clicking the node, you can remove it as well.
We will create a webform with client side code only. We will need to include some 'links' and 'Scripts' to the Head
part of the page so that we can have required files to run this plug in.
Head: Please include the below files to the Head of HTML
<link href="http://cdn.kendostatic.com/2013.2.716/styles/kendo.common.min.css"
rel="stylesheet" />
<link href="http://cdn.kendostatic.com/2013.2.716/styles/kendo.default.min.css"
rel="stylesheet" />
<link href="http://cdn.kendostatic.com/2013.2.716/styles/kendo.dataviz.min.css"
rel="stylesheet" />
<link href="http://cdn.kendostatic.com/2013.2.716/styles/kendo.mobile.all.min.css"
rel="stylesheet" />
<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>
<script src="http://cdn.kendostatic.com/2013.2.716/js/kendo.all.min.js"></script>
The above fields are links to resource files from Telerik Kendo. You can get them by clicking on the files or you can manually download the from Telerik itself. 4th script is jquery files.
Now let us move to the Body
part of the page.
BODY: Place the following HTML to body
<form id="form1" runat="server">
<div>
<p><label id="lblselected"></label></p>
<div id="lblSelectTree">
<select id="multiselect" multiple="multiple"
placeholder="select leagal topics">
<option value="" disabled selected>Select your option</option>
</select>
</div>
<div id="container" style="float: left; min-width: 175px;
background-color: rgb(198, 198, 198);">
<span><input type="text" id="treeViewSearchInput"
placeholder=" -- select --" /><input id="treeviewDropdownBtn"
type="button" value="V" /></span>
<div id="treeview" style="display: none;">
</div>
</div>
</div>
</form>
As you can see, here we use a 'Label
' to display the selected value, a 'div
' to bind the dropdown items.
We are using Telerik Kendo Multiselect to display the list of selected tree nodes.
To search, we are using an 'input
' of type text (it can be of type 'search
'). After this, we also used an 'input
' of type button to act as Dropdown explorer button.
CSS: We have also used little CSS to make it more attractive and dropdown like the design. I've used the following CSS.
<style type="text/css" scoped>
span.k-in > span.highlight
{
background: #7EA700;
color: #ffffff;
border: 1px solid green;
padding: 1px;
}
.sele {
font-weight:bold;
}
</style>
JavaScript: Now next is the big part that is the JavaScript/JQuery code which is all responsible to make the plug in work. Please go through the code carefully to understand it, although it's self-explanatory.
<script type="text/javascript">
var selectedVlaues = [];
var multiSelect;
function createMultiSelect() {
multiSelect = $("#multiselect").kendoMultiSelect({
optionLabel: "Select Legal Topics...",
dataTextField: "text",
dataValueField: "value",
readonly: true,
disabled: true
}).data("kendoMultiSelect");
multiSelect.readonly();
}
function InitSearch(treeViewId, searchInputId, treeviewDropdownBtn) {
var tv = $(treeViewId).data('kendoTreeView');
$(searchInputId).on('keyup', function () {
$(treeViewId + ' li.k-item').show();
$('span.k-in > span.highlight').each(function () {
$(this).parent().text($(this).parent().text());
});
if ($.trim($(this).val()) === '') {
tv.select()
.find("span.k-state-selected")
.removeClass("k-state-selected");
$('#lblselected').html("Selecting: --");
return;
}
var term = this.value.toUpperCase();
var tlen = term.length;
$(treeViewId + ' span.k-in').each(function (index) {
var text = $(this).text();
var html = '';
var q = 0;
var p;
while ((p = text.toUpperCase().indexOf(term, q)) >= 0) {
html += text.substring(q, p) + '<span class="highlight">' +
text.substr(p, tlen) + '</span>';
q = p + tlen;
}
if (q > 0) {
html += text.substring(q);
$(this).html(html);
$(this).parentsUntil('.k-treeview').filter
('.k-item').each(function (index, element) {
tv.expand($(this));
$(this).data('SearchTerm', term);
});
}
});
$(treeViewId + ' li.k-item:not(:has(".highlight"))').hide();
});
$(searchInputId).on('blur', function () {
if ($('#treeViewSearchInput').val() == '')
{
} else {
$('#treeview').show();
}
});
$(searchInputId).on('focus', function () {
$('#treeview').show();$('#treeViewSearchInput').keyup();
});
$(treeviewDropdownBtn).on('click', function () {
$('#treeview').toggle();
});
$('#treeview').on('show', function() {
SetSelectedNodes();
});
}
(function ($) {
$.each(['show', 'hide'], function (i, ev) {
var el = $.fn[ev];
$.fn[ev] = function () {
this.trigger(ev);
return el.apply(this, arguments);
};
});
})(jQuery);
$(document).ready(function () {
var $tv = $("#treeview").kendoTreeView({
dataSource: [
{ id: "1-0", text: "Furniture", expanded: true, items: [
{ id: "1-1", text: "Tables & Chairs" },
{ id: "1-2", text: "Sofas" },
{ id: "1-3", text: "Occasional Furniture" }
] },
{ id: "2-0", text: "Decor", items: [
{ id: "2-1", text: "Bed Linen" },
{ id: "2-2", text: "Curtains & Blinds" },
{ id: "2-3", text: "Carpets" }
] },
{ id: "3-0", text: "Storage" }
],
select: onSelect,
dragAndDrop: true
}).data("kendoTreeView")
InitSearch("#treeview", "#treeViewSearchInput", "#treeviewDropdownBtn");
createMultiSelect();
$('.k-multiselect-wrap').click(function (){
$('#treeview').toggle();
});
});
function onSelect(e) {
var item = this.dataItem(e.node);
$('#treeview').hide();
var item = {text: item.text,value: item.id};
saveMultiselectArray(item, selectedVlaues);
multiSelect.dataSource.data(selectedVlaues);
var values = $.map(multiSelect.dataSource.data(), function (dataItem) {
return dataItem.value;
});
multiSelect.value(values);
e.preventDefault();
}
function saveMultiselectArray(item, arr) {
var found = arr.findIndex(x => x.value==item.value);
if (found >= 0) {
arr.splice(found, 1);
$('#treeViewSearchInput').val('');
$('#lblselected').html('');
} else {
arr.push(item);
$('#treeViewSearchInput').val(item.text);
$('#lblselected').html("Selecting: " + item.text + " & ID:" + item.value);
}
}
function setTreeView() {
if ($('#treeViewSearchInput').val() == '')
{
} else {
$('#treeview').show();
}
}
function SetSelectedNodes(){
var tv = $('#treeview').data('kendoTreeView');
tv.element.find("span.k-in").each(function () {
var item = tv.dataItem(this);
var found = selectedVlaues.findIndex(x => x.value==item.id);
if (found >= 0) {
$(this).addClass('sele');
}else{
$(this).removeClass('sele');
}
});
}
</script>
Please view the previous article for binding the treeview
or you can use json array on the client side.
How Code Works (In Depth Explanations)
For this, I have added the 'Select
' element and convert it to Telerik Multiselect
using the below code:
function createMultiSelect() {
multiSelect = $("#multiselect").kendoMultiSelect({
optionLabel: "Select Legal Topics...",
dataTextField: "text",
dataValueField: "value",
readonly: true,
disabled: true
}).data("kendoMultiSelect");
multiSelect.readonly();
}
The above function is called at page load inside '$(document).ready
' event.
Next, on selecting any element in the tree, I am pushing that into multiselect
using the below code:
saveMultiselectArray(item, selectedVlaues);
function saveMultiselectArray(item, arr) {
var found = arr.findIndex(x => x.value==item.value);
if (found >= 0) {
arr.splice(found, 1);
$('#treeViewSearchInput').val('');
$('#lblselected').html('');
} else {
arr.push(item);
$('#treeViewSearchInput').val(item.text);
$('#lblselected').html("Selecting: " + item.text + " & ID:" + item.value);
}
}
Next, the below code highlights the preselected nodes of the tree by making them bold.
function SetSelectedNodes(){
var tv = $('#treeview').data('kendoTreeView');
tv.element.find("span.k-in").each(function () {
var item = tv.dataItem(this);
var found = selectedVlaues.findIndex(x => x.value==item.id);
if (found >= 0) {
$(this).addClass('sele');
}else{
$(this).removeClass('sele');
}
});
}
Now, we are all ready to test our code. Just paste the code in your project on respective position of page and run the project.
Points of Interest
This (Kendo) is one of the most impressive things I ever found for web development as it provides full customization and control to the developer and with little modification, you can create anything and everything you want. Following are the interesting features of this control.
- Treeview in Dropdown: This will automatically convert your data to
Treeview
like structure on the basic of Json string
supplied.
Note: The Json string is all responsible that tells Kendo about Parent and Child of the node. So please observe the Json string
carefully.
- Searching: From the input box on the top, you can start type and voila!! your data be filtered in the dropdown. Isn't it bolt fast?
- Highlighted Text: As soon as you type a keyword, you will see the filtration with matching text highlighted.
- Multiselected Item: You can see the selected item to the input box just like the selected item in the dropdown.
Thanks for reading!
That's all about the Treeview Dropdown With Multiselect with filtering, fully client-side controlled. Any comments, suggestions are welcome. Please do leave your feedback and appropriate query. I will reply to you for sure.