Удобные выпадающие меню с несколькими вариантами выбора
Я пытаюсь расширить плавный плагин для поддержки нескольких вариантов в раскрывающемся списке. Я уже пробовал расширить базовый редактор, встроенный в библиотеку, изменив "dropdownEditor", как было предложено https://github.com/trebuchetty/Handsontable-select2-editor/issues/7. Я часами читал и просматривал источники ключевых слов, но я не придумываю ничего реального.
Я не возражаю, если на это ответят с помощью расширения Angular или другого родного ECMA5 или 6 способов расширения https://github.com/handsontable/handsontable плагин.
До сих пор мои единственные мысли заключались в том, чтобы на самом деле расширить рамки с помощью этого бита кода, следуя существующим шаблонам. Я добавил все LOC ниже, которые указывают на: multiselect
или Handsontable.MultiselectDropdownCell
скопировал метод dropdown
, названный новым именем, и все работает, однако все еще не может видеть, где я мог бы найти то, что я ищу.
Handsontable.MultiselectDropdownCell = {
editor: getEditorConstructor('multiselectdropdown'),
renderer: getRenderer('autocomplete')
};
Handsontable.cellTypes = {
text: Handsontable.TextCell,
date: Handsontable.DateCell,
numeric: Handsontable.NumericCell,
checkbox: Handsontable.CheckboxCell,
autocomplete: Handsontable.AutocompleteCell,
handsontable: Handsontable.HandsontableCell,
password: Handsontable.PasswordCell,
dropdown: Handsontable.DropdownCell,
multiselect: Handsontable.MultiselectDropdownCell
};
Handsontable.cellLookup = { validator: {
numeric: Handsontable.NumericValidator,
autocomplete: Handsontable.AutocompleteValidator
}};
У меня есть модифицированная версия редактора выпадающего списка, которая выглядит так:
import {getEditor, registerEditor} from './../editors.js';
import {AutocompleteEditor} from './autocompleteEditor.js';
/**
* @private
* @editor MultiSelectDropdownEditor
* @class MultiSelectDropdownEditor
* @dependencies AutocompleteEditor
*/
class MultiSelectDropdownEditor extends AutocompleteEditor {
prepare(row, col, prop, td, originalValue, cellProperties) {
super.prepare(row, col, prop, td, originalValue, cellProperties);
this.cellProperties.filter = false;
this.cellProperties.strict = true;
}
}
export {MultiSelectDropdownEditor};
registerEditor('multiselectdropdown', MultiSelectDropdownEditor);
В этот момент я не знаю, где происходит событие click, когда пользователь выбирает элемент из выпадающего списка. Отладка была болезненной для меня, потому что она через Трейсера. Я попытался настроить событие щелчка после того, как модуль готов, а DOM тоже, но я не могу получить предупреждение даже при нажатии на одну из выделенных выпадающих ячеек. "Нормальные" ячейки я могу получить щелчок простым:
$('body').on('click','#handsontable td', someAlert)
Однако это не так для содержимого меню. Щелчок правой кнопкой мыши, чтобы просмотреть раскрывающееся меню, означает сначала отключить контекстное меню, как на http://handsontable.com/. Затем вы заметите, что щелчок правой кнопкой мыши для проверки чего-либо приведет к событию, закрывающему раскрывающееся меню, которое вы пытаетесь проверить.
Я поставил точки останова по всему исходному коду библиотек, я не могу понять это.
Единственное, что я хочу сделать, это выяснить, где часть кода, которая выделяет элемент меню и устанавливает его на активный выбор, превращает это в метод, который принимает несколько выборов (вплоть до всего массива опций доступно, нажатие активного элемента отключит его, просто скажу).
Затем убедитесь, что эти выборки действительно находятся в области "Доступные данные".
Вот оно, мне не нужно даже рисовать в камере то, что было выбрано, хотя любая помощь там была бы замечательной, потому что, к сожалению, мне еще предстоит найти место, когда параметры в выпадающем меню отображаются либо.
Я также пробовал использовать Select2Editor для handsontable, как показано http://jsfiddle.net/4mpyhbjw/40/ и https://github.com/trebuchetty/Handsontable-select2-editor/issues/3, однако это не очень помогает моей причине.
Вот как выглядит раскрывающаяся ячейка в handsontable:
http://docs.handsontable.com/0.15.1/demo-dropdown.html
Наконец, heres a скрипт: http://jsfiddle.net/tjrygch6/
Я был бы очень признателен, если бы кто-то мог помочь мне здесь. Спасибо, SO!
UPDATE
Мне удалось проанализировать значения в ячейке и превратить этот тип в массив, содержащий значения (поэтому набрав красный синий цвет, он будет содержать массив, содержащий ['red','blue']
). Я запустил этот массив через внутренний алгоритм сортировки, который анализирует параметры и возвращает индекс соответствующего элемента. Я получаю эту работу отлично, и теперь я передаю массив методу выделения. Этот метод передает значения основной библиотеки WalkOnTable. Я не вижу, где я могу изменить логику, чтобы выбрать более одного значения вместо того, чтобы не высвечивать первый вариант.
this.selectCell = function(row, col, endRow, endCol, scrollToCell, changeListener) {
var coords;
changeListener = typeof changeListener === 'undefined' || changeListener === true;
if (typeof row !== 'number' && !Array.isArray(row) || row < 0 || row >= instance.countRows()) {
return false;
}
if (typeof col !== 'number' || col < 0 || col >= instance.countCols()) {
return false;
}
if (typeof endRow !== 'undefined') {
if (typeof endRow !== 'number' || endRow < 0 || endRow >= instance.countRows()) {
return false;
}
if (typeof endCol !== 'number' || endCol < 0 || endCol >= instance.countCols()) {
return false;
}
}
// Normal number value, one item typed in
if (!Array.isArray(row) && typeof row === 'number'){
coords = new WalkontableCellCoords(row, col);
walkSelection(coords);
}
Это место, где мне кажется, что мне нужно WalkontableCellCoords
изменить, чтобы принять массив, а затем выделить и выбрать оба значения при открытии и закрытии раскрывающегося списка. Мне также нужно иметь возможность выбирать несколько опций с помощью сенсорного или клик-события.
else {
// Array found, apply to each value
new WalkontableCellCoords(row[0], col);
new WalkontableCellCoords(row[1], col);
}
function walkSelection(coords){
priv.selRange = new WalkontableCellRange(coords, coords, coords);
if (document.activeElement && document.activeElement !== document.documentElement && document.activeElement !== document.body) {
document.activeElement.blur();
}
if (changeListener) {
instance.listen();
}
if (typeof endRow === 'undefined') {
selection.setRangeEnd(priv.selRange.from, scrollToCell);
} else {
selection.setRangeEnd(new WalkontableCellCoords(endRow, endCol), scrollToCell);
}
instance.selection.finish();
}
return true;
};
Обновление 2
Я получил внутренние методы для распознавания и частичного выбора обоих значений в DOM, но он еще далек от правильного.
![Отображение выбора (вида) обоих элементов на основе двух значений, введенных в ячейку, также показывающий вывод в консоли для того, чтобы координата была возвращена из утилиты WalkOnTable, используемой за кулисами этого плавного подключаемого модуля. Выходной сигнал ниже]()
Здесь вызывается вывод консоли, сгенерированный методом WalkOnTableCellCords
, который, как представляется, выделяет выпадающий выбор в случае, когда ячейка содержит только 1 значение (функция по умолчанию). Этот вывод состоит из ввода черного синего цвета в выпадающую ячейку, содержащую как синий, так и черный, как отдельные параметры в списке.
extended_hot_v15-01.js:5041 DropdownEditor {
"highlight": {
"row": 6,
"col": 0
},
"from":
{
"row": 4,
"col": 0
},
"to": {
"row": 6,
"col": 0
}
}
ОБНОВЛЕНИЕ. Если кто-то решит это, я лично вылечу туда, где вы лично, и пожимаете руку. ДВАЖДЫ.
Ответы
Ответ 1
Ого. Столько усилий. Теперь, более года спустя, это намного проще.
Я успешно использовал выбранный плагин jQuery. Это было довольно легко.
Вот пример одного человека:
https://github.com/mydea/handsontable-chosen-editor
Выбран красивый. Я использую автозаполнение с мультиселекцией. Здесь средство визуализации:
function customDropdownRenderer(instance, td, row, col, prop, value, cellProperties) {
var selectedId;
var optionsList = cellProperties.chosenOptions.data;
if(typeof optionsList === "undefined" || typeof optionsList.length === "undefined" || !optionsList.length) {
Handsontable.TextCell.renderer(instance, td, row, col, prop, value, cellProperties);
return td;
}
var values = (value + "").split(",");
value = [];
for (var index = 0; index < optionsList.length; index++) {
if (values.indexOf(optionsList[index].id + "") > -1) {
selectedId = optionsList[index].id;
value.push(optionsList[index].label);
}
}
value = value.join(", ");
Handsontable.TextCell.renderer(instance, td, row, col, prop, value, cellProperties);
return td;
}
а затем я просто установил конкретный столбец следующим образом:
columns: [
{},
{},
{type: 'numeric'},
{type: 'dropdown', source: ['', 'NAME', 'FNB']},
{},
{},
{},
{},
{},
{},
{},
{type: 'dropdown', source: ['', 'S', 'M']},
{},
{},
{
renderer: customDropdownRenderer,
editor: "chosen",
width: 150,
chosenOptions: {
multiple: true,
data: productData
}
},
{},
{editor: false, readOnly: true, width: 1},
{editor: false, readOnly: true, width: 1}
],
Ответ 2
Хорошо, надеюсь, это поможет вам. Мне потребовалось время, чтобы прочитать api и настроить код:)
Я взял образец кода из библиотеки Handsontable
(последняя версия) и внес небольшие изменения.
В нем могут быть некоторые ошибки, но это только прототип, поэтому вы можете редактировать и, конечно же, выглядеть лучше.
По какой-то причине я не смог сделать клик dropdownlist
доступным. Это похоже на проблему z-index или другие игры css-свойств. Я верю, что вы найдете, как это исправить.
В любом случае, вы можете использовать клавиатуру для выбора, удерживая shift для множественного выбора.
Вывод представляет собой набор объединенных выбранных опций разделенным запятой.
например:
![введите описание изображения здесь]()
Чтобы сделать эту работу, добавьте этот код после загрузки handsontable libary. Он расширит ваши типы Handsontable
.
(function(Handsontable) {
var SelectEditor = Handsontable.editors.BaseEditor.prototype.extend();
SelectEditor.prototype.init = function() {
// Create detached node, add CSS class and make sure its not visible
this.select = document.createElement('SELECT');
Handsontable.Dom.addClass(this.select, 'htSelectEditor');
this.select.style.display = 'none';
// Attach node to DOM, by appending it to the container holding the table
this.instance.rootElement.appendChild(this.select);
};
// Create options in prepare() method
SelectEditor.prototype.prepare = function() {
// Remember to invoke parent method
Handsontable.editors.BaseEditor.prototype.prepare.apply(this, arguments);
this.isMultiple = !!this.cellProperties.multiple;
if (this.isMultiple) this.select.multiple = true;
var selectOptions = this.cellProperties.selectOptions;
var options;
if (typeof selectOptions == 'function') {
options = this.prepareOptions(selectOptions(this.row,
this.col, this.prop))
} else {
options = this.prepareOptions(selectOptions);
}
Handsontable.Dom.empty(this.select);
for (var option in options) {
if (options.hasOwnProperty(option)) {
var optionElement = document.createElement('OPTION');
optionElement.value = option;
Handsontable.Dom.fastInnerHTML(optionElement, options[option]);
this.select.appendChild(optionElement);
}
}
};
SelectEditor.prototype.prepareOptions = function(optionsToPrepare) {
var preparedOptions = {};
if (Array.isArray(optionsToPrepare)) {
for (var i = 0, len = optionsToPrepare.length; i < len; i++) {
preparedOptions[optionsToPrepare[i]] = optionsToPrepare[i];
}
} else if (typeof optionsToPrepare == 'object') {
preparedOptions = optionsToPrepare;
}
return preparedOptions;
};
SelectEditor.prototype.getValue = function() {
var result = [];
var options = this.select && this.select.options;
var opt;
for (var i = 0, iLen = options.length; i < iLen; i++) {
opt = options[i];
if (opt.selected) {
result.push(opt.value || opt.text);
}
}
return result.join();
};
SelectEditor.prototype.setValue = function(value) {
this.select.value = value;
};
SelectEditor.prototype.open = function() {
var width = Handsontable.Dom.outerWidth(this.TD);
// important - group layout reads together for better performance
var height = Handsontable.Dom.outerHeight(this.TD);
var rootOffset = Handsontable.Dom.offset(this.instance.rootElement);
var tdOffset = Handsontable.Dom.offset(this.TD);
var editorSection = this.checkEditorSection();
var cssTransformOffset;
if (this.select && this.select.options && this.isMultiple) {
var height = 0;
for (var i = 0; i < this.select.options.length - 1; i++) {
height += Handsontable.Dom.outerHeight(this.TD);
}
}
switch (editorSection) {
case 'top':
cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.vertical.clone.wtTable.holder.parentNode);
break;
case 'left':
cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.horizontal.clone.wtTable.holder.parentNode);
break;
case 'corner':
cssTransformOffset = Handsontable.Dom.getCssTransform(this.instance.view.wt.wtScrollbars.corner.clone.wtTable.holder.parentNode);
break;
}
var selectStyle = this.select.style;
if (cssTransformOffset && cssTransformOffset !== -1) {
selectStyle[cssTransformOffset[0]] = cssTransformOffset[1];
} else {
Handsontable.Dom.resetCssTransform(this.select);
}
selectStyle.height = height + 'px';
selectStyle.minWidth = width + 'px';
selectStyle.top = tdOffset.top - rootOffset.top + 'px';
selectStyle.left = tdOffset.left - rootOffset.left + 'px';
selectStyle.margin = '0px';
selectStyle.display = '';
};
SelectEditor.prototype.checkEditorSection = function() {
if (this.row < this.instance.getSettings().fixedRowsTop) {
if (this.col < this.instance.getSettings().fixedColumnsLeft) {
return 'corner';
} else {
return 'top';
}
} else {
if (this.col < this.instance.getSettings().fixedColumnsLeft) {
return 'left';
}
}
};
SelectEditor.prototype.close = function() {
this.select.style.display = 'none';
};
Handsontable.editors.registerEditor('dvirH', SelectEditor);
})(Handsontable);
Способ использования:
var container = document.getElementById("example1");
var hot1;
hot1 = new Handsontable(container, {
data: [
['2008', 'Nissan', 11],
['2009', 'Honda', 11],
['2010', 'Kia', 15]
],
colHeaders: true,
contextMenu: false,
columns: [{}, {
editor: 'select',
selectOptions: ['Kia', 'Nissan', 'Toyota', 'Honda'],
// notice that attribute. You can remove it to get a regular select
multiple: true
} {}]
});
Демо-версия в здесь
Чтобы вам было легко. Если вы хотите отредактировать код, вы можете изменить 2 метода.
-
prepare
- будет вызываться каждый раз, когда пользователь запускает событие открытия редактора. Для конфигураций и манипуляций.
-
init
- этот метод будет вызываться каждый раз, когда вы нажимаете на ячейку. Он создает html-код, поэтому вы можете изменить его на флажки, например.
Еще одна вещь относится к вашим вопросам о том, где вещи в коде.
Совместим с любыми типами ячеек для редактора и рендеринга.
Весь HTML-код редактора, вероятно, существует в init
, если вы хотите изменить один из них.
value
, который представляет собой содержимое html, которое появляется в ячейке, когда вы находитесь не в режиме редактирования, существует в методе getValue
.
Я надеюсь, что это поможет, и я надеюсь, что это соответствует вашей текущей версии.
Ответ 3
С jExcel вы можете получить гораздо большую поддержку, чтобы справиться с этим.
https://bossanova.uk/jexcel/examples/working-with-dropdowns
<html>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jexcel/2.1.0/js/jquery.jexcel.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jexcel/2.1.0/js/jquery.jdropdown.js"></script>
<link rel="stylesheet" href="#" onclick="location.href='https://cdnjs.cloudflare.com/ajax/libs/jexcel/2.1.0/css/jquery.jexcel.min.css'; return false;" type="text/css" />
<link rel="stylesheet" href="#" onclick="location.href='https://cdnjs.cloudflare.com/ajax/libs/jexcel/2.1.0/css/jquery.jdropdown.min.css'; return false;" type="text/css" />
<div id="my"></div>
<script>
data2 = [
[3, 'Cheese', 0],
[1, 'Apples', 1],
[2, 'Carrots', 0],
[1, 'Oranges', 0],
];
dropdown = function(instance, cell, c, r, source) {
// Get a value from the same row but previous column
var value = $(instance).jexcel('getValue', c-1 + '-' + r);
// Return the values will be part in your current column
if (value == 1) {
return ['Apples','Bananas','Oranges'];
} else if (value == 2) {
return ['Carrots'];
} else {
return source;
}
}
$('#my2').jexcel({
data:data2,
colHeaders: ['Category','Product', 'Buy later'],
colWidths: [ 300, 200, 100 ],
columns: [
{ type: 'dropdown', source: [ {'id':'1', 'name':'Fruits'}, {'id':'2', 'name':'Legumes'}, {'id':'3', 'name':'General Food'} ] },
{ type: 'dropdown', source: [ 'Apples', 'Bananas', 'Carrots', 'Oranges', 'Cheese' ], filter:dropdown },
{ type: 'checkbox' },
]
});
</script>
</html>