Древовидные checkbox
Продолжая тематику предыдущего поста, сегодня речь пойдет о древовидных чекбоксах.
Они опять же чаще всего используются в системе фильтров, когда есть возможность выбрать (или отсеять) группы или подгруппы объектов. При этом немаловажным является не только понятное отображение для пользователя, но также и то, в каком виде запрос будет отправлен серверу.
Я предлагаю несложный рецепт, который вы сможете применить у себя в проекте, соответственно, допилив под свои нужды.
Задана двухуровневая система фильтров (категория\подкатегория), и пользователь может выбрать отдельные подкатегории, либо целую категорию (допустим подкатегория — город; категория — страна).
При выборе категории целиком удобнее оперировать именно ей, а не списком подкатегорий, поэтому на сервер отправим лишь категорию. Если же выбраны не все подкатегории, то отправим список выбранных элементов.
приведу код обработки с комментариями:
$(document).ready(function()< //Отображаем\скрываем потомков checkbox_ов $('.checkbox-area .spoiler').click(function()< var block = $(this).parent('li').children('ul'); if ($(block).is(':hidden'))< $(block).slideDown(100); $(this).removeClass('closed'); >else < $(block).slideUp(100); $(this).addClass('closed'); >return false; >) //Изменение состояния $('.checkbox-area .checkbox input').live('change', function() < var cur_obj = $(this); // Если выбрано ВСЕ if (!$(cur_obj).is('.all_filter')) $('.checkbox-area input.all_filter').removeAttr('checked').parent().parent('li').removeClass('checked'); if ($(cur_obj).parent().parent('li').find('input:checkbox').length >1)< // Если это родитель var childinputs = $(cur_obj).parent().parent('li').find('input:checkbox'); // Если текущий объект выбран if ($(cur_obj).is(':checked'))< $(childinputs).removeAttr('checked').parent().parent('li').addClass('checked'); $(cur_obj).attr('checked', 'checked').parent().parent('li').addClass('checked').removeClass('notall'); >else < $(childinputs).removeAttr('checked').parent().parent('li').removeClass('checked'); >if ($(cur_obj).parent().parent('li').children('a').is('.closed')) < $(cur_obj).parent().parent('li').children('a').removeClass('closed'); $(cur_obj).parent().parent('li').children('ul').slideDown(200); >>else< // Если это дочерний элемент var parent_li = $(cur_obj).parents('ul.child').parent('li'); if ($(cur_obj).parent().parent('li').is('.checked'))< // Если элемент уже выбран $(cur_obj).parent().parent('li').removeClass('checked'); $(cur_obj).removeAttr('checked'); >else < // Если мы выбираем этот элемент $(cur_obj).parent().parent('li').addClass('checked'); $(cur_obj).attr('checked','checked'); >var boxes = $(cur_obj).parents('ul.child').find('li'); var boxes_checked = $(cur_obj).parents('ul.child').find('li.checked'); if (boxes.length == boxes_checked.length && boxes_checked.length > 0)< // если были выбраны все $(parent_li).addClass('checked').removeClass('notall').attr('ckecked','ckecked'); $(boxes_checked).find('input').removeAttr('checked'); $(parent_li).children('.checkbox').children('input').attr('checked','checked'); >else< // если выбраны НЕ все if (boxes_checked.length == 0)< // Совсем ни одного $(cur_obj).parents('ul.child').find('input').removeAttr('checked'); $(parent_li).removeClass('notall'); >else < $(parent_li).find('.checked').children().children('input').attr('checked','checked'); $(parent_li).addClass('notall').removeClass('checked'); >$(parent_li).removeClass('checked').children('.checkbox').children('input').removeAttr('checked'); > > if ($(cur_obj).is('.all_filter'))< if ($(cur_obj).is(':checked'))< $(cur_obj).parents('ul').find('input:checkbox').removeAttr('checked').parent().parent('li').removeClass('checked').removeClass('notall'); $(cur_obj).parent().parent('li').addClass('checked'); >else < $(cur_obj).parents('ul').find('input:checkbox').removeAttr('checked').parent().parent('li').removeClass('checked').removeClass('notall'); >> >) // Просчет состояния $('.checkbox-area .checkbox :checked').parents('li').addClass('checked'); $('.checkbox-area ul.child').each(function() < var cur_obj = $(this); var parent_li = $(cur_obj).parent('li'); var boxes = $(cur_obj).find('li'); var boxes_checked = $(cur_obj).find('li.checked'); if (boxes.length == boxes_checked.length && boxes_checked.length >0)< // если были выбраны все $(parent_li).addClass('checked').removeClass('notall').attr('ckecked','ckecked'); $(boxes_checked).find('input').removeAttr('checked'); $(parent_li).children('.checkbox').children('input').attr('checked','checked'); >else< // если выбраны НЕ все if (boxes_checked.length == 0)< // Совсем ни одного $(parent_li).removeClass('notall'); $(parent_li).children('a').addClass('closed'); $(parent_li).children('ul.child').hide(); >else < $(parent_li).find('.checked').children().children('input').attr('checked','checked'); $(parent_li).addClass('notall').removeClass('checked'); >> if ($(parent_li).children('.checkbox').children('input').is(':checked')) < $(parent_li).find('li').addClass('checked'); $(parent_li).children('a').removeClass('closed'); $(parent_li).children('ul.child').show(); >>) if ($('.checkbox-area input:checkbox:checked').length == 0) < $('.checkbox-area input.all_filter').attr('checked', 'checked').parent().parent('li').addClass('checked'); >>)
How TO — Tree View
Learn how to create a tree view with CSS and JavaScript.
Tree View
A tree view represents a hierarchical view of information, where each item can have a number of subitems.
Click on the arrow(s) to open or close the tree branches.
- Beverages
- Water
- Coffee
- Tea
- Black Tea
- White Tea
- Green Tea
- Sencha
- Gyokuro
- Matcha
- Pi Lo Chun
Tree View
Step 1) Add HTML:
Example
Step 2) Add CSS:
Example
/* Remove default bullets */
ul, #myUL list-style-type: none;
>/* Remove margins and padding from the parent ul */
#myUL margin: 0;
padding: 0;
>/* Style the caret/arrow */
.caret cursor: pointer;
user-select: none; /* Prevent text selection */
>/* Create the caret/arrow with a unicode, and style it */
.caret::before content: «\25B6»;
color: black;
display: inline-block;
margin-right: 6px;
>/* Rotate the caret/arrow icon when clicked on (using JavaScript) */
.caret-down::before transform: rotate(90deg);
>/* Hide the nested list */
.nested display: none;
>/* Show the nested list when the user clicks on the caret/arrow (with JavaScript) */
.active display: block;
>Step 3) Add JavaScript:
Example
var toggler = document.getElementsByClassName(«caret»);
var i;for (i = 0; i < toggler.length; i++) toggler[i].addEventListener("click", function() this.parentElement.querySelector(".nested").classList.toggle("active");
this.classList.toggle(«caret-down»);
>);
>Checkbox Tree View
In this example, we use a «ballot box» unicode instead of a caret:
Раскрывающийся многоуровневый список
В данном примере описано как вывести многоуровневый список checkbox и radio button из БД с помощью jQuery плагина treeview. Плагин делает удобный древовидный список из вложенных тегов
- . Скачать его можно с GitHub. Данные будем брать из таблицы `category` с полями `id` , `name` и `parent` . В поле `parent` хранится id родителя. Получаем все записи из таблицы используя расширение PDO:
$dbh = new PDO('mysql:dbname=db_name;host=localhost', 'логин', 'пароль'); $sth = $dbh->prepare("SELECT * FROM `category` ORDER BY `name`"); $sth->execute(); $category = $sth->fetchAll(PDO::FETCH_ASSOC);
function convert($array, $i = 'id', $p = 'parent') < if (!is_array($array)) < return array(); >else < $ids = array(); foreach ($array as $k =>$v) < if (is_array($v)) < if ((isset($v[$i]) || ($i === false)) && isset($v[$p])) < $key = ($i === false) ? $k : $v[$i]; $parent = $v[$p]; $ids[$parent][$key] = $v; >> > return (isset($ids[0])) ? convert_node($ids, 0, 'children') : false; > > function convert_node($index, $root, $cn) < $_ret = array(); foreach ($index[$root] as $k =>$v) < $_ret[$k] = $v; if (isset($index[$k])) < $_ret[$k][$cn] = convert_node($index, $k, $cn); >> return $_ret; > $category = convert($category);
.treeview label < margin: 0; display: inline-block; font-size: 12px; font-weight: normal; line-height: 14px; vertical-align: top; cursor: pointer; >.treeview input
Раскрывающийся многоуровневый список
В данном примере описано как вывести многоуровневый список checkbox и radio button из БД с помощью jQuery плагина treeview. Плагин делает удобный древовидный список из вложенных тегов
- . Скачать его можно с GitHub. Данные будем брать из таблицы `category` с полями `id` , `name` и `parent` . В поле `parent` хранится id родителя. Получаем все записи из таблицы используя расширение PDO:
$dbh = new PDO('mysql:dbname=db_name;host=localhost', 'логин', 'пароль'); $sth = $dbh->prepare("SELECT * FROM `category` ORDER BY `name`"); $sth->execute(); $category = $sth->fetchAll(PDO::FETCH_ASSOC);
function convert($array, $i = 'id', $p = 'parent') < if (!is_array($array)) < return array(); >else < $ids = array(); foreach ($array as $k =>$v) < if (is_array($v)) < if ((isset($v[$i]) || ($i === false)) && isset($v[$p])) < $key = ($i === false) ? $k : $v[$i]; $parent = $v[$p]; $ids[$parent][$key] = $v; >> > return (isset($ids[0])) ? convert_node($ids, 0, 'children') : false; > > function convert_node($index, $root, $cn) < $_ret = array(); foreach ($index[$root] as $k =>$v) < $_ret[$k] = $v; if (isset($index[$k])) < $_ret[$k][$cn] = convert_node($index, $k, $cn); >> return $_ret; > $category = convert($category);
.treeview label < margin: 0; display: inline-block; font-size: 12px; font-weight: normal; line-height: 14px; vertical-align: top; cursor: pointer; >.treeview input
Collapsible Tree View With Checkboxes — jQuery hummingbird-treeview
hummingbird-treeview is a jQuery plugin that transforms nested html lists into an expandable, collapsible, searchable, checkable, hierarchical tree structure with lots of useful options and APIs.
Also includes support for ‘indeterminate’ state in the checkbox inputs.
See also:
How to use it:
1. Create an HTML tree of nested unordered lists as follows. The data-str attribute is used to add more custom functionality to the nodes.
2. Download and load the jQuery hummingbird-treeview plugin’s files along with the jQuery library into the document.
3. Load the Font Awesome (4 or 5) for the necessary icons.
4. Just initialize the plugin and done.
5. Available data attributes:
- data-height: Height of the tree view
- data-scroll: Determine if the tree view is scrollable
- data-id: Unique ID
- data-boldParents: set the text of all parent nodes to BOLD
- data-css: inject arbitrary CSS, except text colors and background colors
- data-nonHoverColor
- data-nonHoverColor_bg
- data-HoverColor
- data-HoverColor_bg
6. Override the global settings.
// Font Awesome prefix // "fas" or "far" for Font Awesome 5 $.fn.hummingbird.defaults.SymbolPrefix = "fa" // Collapsed Symbol $.fn.hummingbird.defaults.collapsedSymbol = "fa-plus"; // Expand Symbol $.fn.hummingbird.defaults.expandedSymbol = "fa-minus"; // Collapse all nodes on init $.fn.hummingbird.defaults.collapseAll = true; // Enable checkboxes $.fn.hummingbird.defaults.checkboxes = "enabled"; // Set this to "disabled" to disable all checkboxes from nodes that are parents $.fn.hummingbird.defaults.checkboxesGroups= "enabled"; // New option singleGroupOpen to allow only one group to be open and collapse all others. // The number provided defines the level to which the function should be applied (starting at 0). $.fn.hummingbird.defaults.singleGroupOpen = -1; // Enable a mouse hover effect on items $.fn.hummingbird.defaults.hoverItems = false; // Set this to true to enable the functionality to account for n-tuples (doubles, triplets, . ). $.fn.hummingbird.defaults.checkDoubles = false; // Or "bootstrap" to use Bootstrap's styles $.fn.hummingbird.defaults.hoverMode = "html"; // Background color on hover $.fn.hummingbird.defaults.hoverColorBg1 = "#6c757c"; // Background color on non hover $.fn.hummingbird.defaults.hoverColorBg2 = "white"; // Text color on hover $.fn.hummingbird.defaults.hoverColorText1 = "white"; // Text color on non hover $.fn.hummingbird.defaults.hoverColorText2 = "black"; // Use Bootstrap colors $.fn.hummingbird.defaults.hoverColorBootstrap = "bg-secondary text-white"; // Set this to "enabled" to add collapse and expand functionality to a click on a parent node name. $.fn.hummingbird.defaults.clickGroupsToggle = "disabled";
// check all nodes $("#treeview").hummingbird("checkAll"); // uncheck all nodes $("#treeview").hummingbird("uncheckAll"); // collapse all nodes $("#treeview").hummingbird("collapseAll"); // expand all nodes $("#treeview").hummingbird("expandAll"); // check a specific node $("#treeview").hummingbird("checkNode",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], >); // uncheck a specific node $("#treeview").hummingbird("uncheckNode",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], >); // expand a specific node $("#treeview").hummingbird("expandNode",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], expandParents:false >); // collapse a specific node $("#treeview").hummingbird("collapseNode",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], collapseChildren:false >); // Disables expand and collapse functionality of a node, which is identified by its id or data-id, which has to be defined in the attr parameter. The name parameter holds the name of the id or data-id. $("#treeview").hummingbird("disableToggle",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], >); // disable a specific node $("#treeview").hummingbird("disableNode",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], state:true, disableChildren:true, >); // enable a specific node $("#treeview").hummingbird("enableNode",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], state:true, disableChildren:true, >); // hide a node $("#treeview").hummingbird("hideNode",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], state:true, disableChildren:true, >); // show a node $("#treeview").hummingbird("showNode",< sel:"id", // "id", "data-id" or "text" vals:["hum_1","hum_2","hum_3"], state:true, disableChildren:true, >); // disable parent node on collapse $("#treeview").hummingbird("showNode",< sel:"id", vals: ["hum_5","hum_6"], state:true >); // add nodes $("#treeview").hummingbird('addNode',< pos:['after','after'], anchor_sel:['text','id'], anchor_vals:['node-0-1-1-2','hum_5'], text:['New Node1','New Node2'], the_id:['new_id1','new_id2'], data_id:['new_data_id1','new_data_id2'] >); // remove a node $("#treeview").hummingbird('removeNode',< sel:"id", // "id", "data-id" or "text" vals:"node-0-1-1-2", state:true, disableChildren:true, >); // get checked nodes var List = ; $("#treeview").hummingbird(getChecked",< list:List, onlyEndNodes:true, onlyParents:false, fromThis:false >); // get unchecked nodes var List = ; $("#treeview").hummingbird(getUnchecked",< list:List, onlyEndNodes:true, onlyParents:false >); // get indeterminate nodes var List = ; $("#treeview").hummingbird("getIndeterminate",< list:List >); // save the state of the treeview for later rebuilding var treeState = <>; $("#treeview").hummingbird("saveState",< save_state:treeState >); // restore the saved state $("#treeview").hummingbird("restoreState",< restore_state:treeState >); // a function that controls the tri-state functionality $("#treeview").hummingbird("triState"); // Skip firing the CheckUncheckDone event in the following call. // This method can be called before any other method to skip firing the CheckUncheckDone event in the followed method. $("#treeview").hummingbird("skipCheckUncheckDone"); // remove all nodes which NOT match a search patter $("#treeview").hummingbird("filter",< str:".txt|.jpg|test", caseSensitive: false, box_disable:false, onlyEndNodes:false, filterChildren:true >); // If the treeview is embedded in a scrollable (css option: overflow-y: scroll;) container, this container must be identified here as the treeview_container (using the id). Otherwise treeview_container should be set to "body". // The search_input parameter depicts the id of the input element for the search function. // The search_output defines an element to bind the search results on (like the ul in the example below). // The search_button is simply the button for the search. // A scrollOffset in pixels (negative or positive) can be defined to adjust the automatic scoll position. // The best value must be observed by testing. onlyEndNodes is per default false, thus set this to true if the search should include also parent nodes. // The optional parameter dialog is per default empty (""). This parameter can be used for special cases, to bind the treeview to a dynamical created object like a bootstrap modal (pop-up). // In such a case this parameter would be dialog:".modal-dialog". // Three other optional parameters, EnterKey, enter_key_1 and enter_key_2 are available. // EnterKey is per default true and can be set to false. If true the search_button can be triggered with the Enter key. // To avoid interference of the Enter key functionality it can be restricted and only be executable if enter_key_1 == enter_key_2. // These two parameters can be chosen arbitrarily. $("#treeview").hummingbird("search",< treeview_container:"treeview_container", search_input:"search_input", search_output:"search_output", search_button:"search_button", scrollOffset:-515, onlyEndNodes:false >);
$("#treeview").on("nodeChecked", function()< // when checked >); $("#treeview").on("nodeUnchecked", function()< // when unchecked >); $("#treeview").on("CheckUncheckDone", function()< // when checked or unchecked >);
Changelog:
- New data-* attributes to set text colors and background colors for individual nodes: data-nonHoverColor, data-nonHoverColor_bg, data-HoverColor, data-HoverColor_bg.