javascript 具有多个选择的 Handsontable 下拉菜单
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/31931372/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Handsontable dropdowns with multiple selections
提问by Alpha G33k
I am trying to extend the handsontable plugin to support multiple selections in its dropdown list. I have already tried extending the base Editor built into the library by modifying the 'dropdownEditor' as suggested https://github.com/trebuchetty/Handsontable-select2-editor/issues/7. I spent hours reading and searching through the source for keywords but I am not coming up with anything of real use.
我正在尝试扩展 handsontable 插件以支持其下拉列表中的多个选择。我已经尝试按照https://github.com/trebuchetty/Handsontable-select2-editor/issues/7 的建议修改“dropdownEditor”来扩展库中内置的基本编辑器 。我花了几个小时阅读和搜索关键字的来源,但我没有想出任何真正有用的东西。
I do not mind if this is answered using the Angular extension or another native ECMA5 or 6 way of extending the https://github.com/handsontable/handsontableplugin.
我不介意这是使用 Angular 扩展还是其他原生 ECMA5 或 6 扩展https://github.com/handsontable/handsontable插件的方式来回答的。
So far my only thoughts were to actually extend the framework with this bit of code following the patterns that exist. I added all LOC below that are pointing to: multiselect
or Handsontable.MultiselectDropdownCell
copied the dropdown
method, called the new name and everything works, however still cannot see where I could begin to find what I am looking for.
到目前为止,我唯一的想法是按照现有模式使用这段代码来实际扩展框架。我添加了下面指向的所有 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
}};
I have at a modified version of dropdown editor in place that looks like:
我有一个修改过的下拉编辑器版本,如下所示:
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);
At this point I have no clue where the click event is happening when the user selects an item from the dropdown list. Debugging has been painful for me because it is through Traceur. I tried setting a click event after the module is ready and the DOM is as well however I cannot get even an alert to fire based off of a click on one of the select dropdown cells. The 'normal' cells I can get a click with a simple:
在这一点上,当用户从下拉列表中选择一个项目时,我不知道点击事件发生在哪里。调试对我来说很痛苦,因为它是通过 Traceur 进行的。我尝试在模块准备好并且 DOM 准备好后设置一个点击事件,但是我什至无法根据单击一个选择的下拉单元格而触发警报。我可以通过简单的点击“正常”单元格:
$('body').on('click','#handsontable td', someAlert)
$('body').on('click','#handsontable td', someAlert)
However, not so for the menu contents. Right clicking to inspect the dropdown menu means first disabling the context menu like the one on http://handsontable.com/. Then you will notice that right clicking to inspect anything will fire an event that closes the dropdown menu you are trying to inspect.
但是,菜单内容并非如此。右键单击以检查下拉菜单意味着首先禁用上下文菜单,例如http://handsontable.com/上的上下文菜单。然后您会注意到右键单击以检查任何内容将触发关闭您尝试检查的下拉菜单的事件。
I've put breakpoints all through the libraries source code, I cannot figure this one out.
我已经在所有库源代码中放置了断点,但我无法弄清楚这一点。
The only thing I want to do is to figure out where the part of the code that highlights the menu item and sets it to an active selection, turn that into a method that accepts multiple selections (up to the entire array of options available, clicking an active item will disable it lets just say).
我唯一想做的就是找出突出显示菜单项并将其设置为活动选择的代码部分的位置,将其转换为接受多个选择的方法(最多可用选项的整个数组,单击一个活动项目将禁用它,让我们说)。
Then ensuring that those selections are actually in the Handsontable 'data scope'.
然后确保这些选择实际上在 Handsontable 的“数据范围”中。
Thats it, I don't need it to even render in the cell what things have been chosen, although any help there would be great because unfortunately, I am yet to find the spot when the options in the dropdown are rendered either.
就是这样,我什至不需要它来在单元格中呈现已选择的内容,尽管那里的任何帮助都会很棒,因为不幸的是,当下拉列表中的选项呈现时,我还没有找到位置。
I have also tried using the Select2Editor made for handsontable as seen http://jsfiddle.net/4mpyhbjw/40/and https://github.com/trebuchetty/Handsontable-select2-editor/issues/3, however it does not help my cause much. Here is what the dropdown cell in handsontable looks like:
我也尝试过使用为 Handsontable 制作的 Select2Editor,如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
http://docs.handsontable.com/0.15.1/demo-dropdown.html
Finally, heres a fiddle: http://jsfiddle.net/tjrygch6/
最后,这里有一个小提琴:http: //jsfiddle.net/tjrygch6/
I would be super appreciative if someone could help me out here. Thanks SO!
如果有人能在这里帮助我,我将不胜感激。谢谢!
UPDATE
更新
I have managed to parse the values in the cell and turn the type into an array containing the values (so typing red blue will turn an array containing ['red','blue']
) . I have run this array through the internal sort algorithm which parses the options and returns an index of a matching item. I get this working fine and I now am passing the array into the highlight method. This method passes the values the the core library WalkOnTable. I do not see where I can alter the logic to select more than one value instead of unhighlighting the first option.
我已设法解析单元格中的值并将类型转换为包含值的数组(因此键入 red blue 将转换为包含 的数组['red','blue']
)。我已经通过内部排序算法运行这个数组,该算法解析选项并返回匹配项的索引。我让它工作正常,我现在将数组传递给 highlight 方法。此方法将值传递到核心库 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);
}
This is the spot where I think I need WalkontableCellCoords
to be modified to accept an array and then highlight and select both values when the dropdown is opened and closed. I also need to be able to select multiple options via touch or click event.
这是我认为我需要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;
};
};
Update 2
更新 2
I have gotten the internal methods to recognize and partially select both values in the DOM however it is far from correct still.
我已经获得了内部方法来识别和部分选择 DOM 中的两个值,但它仍然远非正确。
Here is the console output generated by the method WalkOnTableCellCords
to be called which seems to be what highlights the dropdown selection in the case where the cell contains only 1 value (default functionality). This output is from typing black blue into a dropdown cell containing both blue and black as individual options in the list.
这是WalkOnTableCellCords
要调用的方法生成的控制台输出,在单元格仅包含 1 个值(默认功能)的情况下,这似乎是突出显示下拉选择的原因。此输出来自在包含蓝色和黑色作为列表中的单独选项的下拉单元格中键入 black blue。
extended_hot_v15-01.js:5041 DropdownEditor {
"highlight": {
"row": 6,
"col": 0
},
"from":
{
"row": 4,
"col": 0
},
"to": {
"row": 6,
"col": 0
}
}
UPDATEIf anyone solves this, I will personally fly to wherever you are in person, and shake your hand. TWICE.
更新如果有人解决了这个问题,我会亲自飞到你所在的任何地方,并与你握手。两次。
采纳答案by Rolok
Wow. So much effort. Now, more than a year later, it is much easier.
哇。这么努力。现在,一年多过去了,事情变得容易多了。
I used the Chosen jQuery plugin successfully. It was pretty easy.
我成功地使用了 Chosen jQuery 插件。这很容易。
Here's one person's example: https://github.com/mydea/handsontable-chosen-editor
这是一个人的例子:https: //github.com/mydea/handsontable-chosen-editor
Chosen is beautiful. I am using autocomplete with a multiselect. Here's the renderer:
选择的很漂亮。我正在使用带有多选的自动完成功能。这是渲染器:
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;
}
and then I just set up the particular column like this:
然后我只是像这样设置特定的列:
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}
],
回答by Dvir
Ok, I hope it will help you. It took me time to read the api and customize the code :)
好的,希望能帮到你。我花了一些时间阅读api并自定义代码:)
I took sample code from Handsontable
library (last version) and made little changes.
我从Handsontable
库(最新版本)中获取了示例代码并做了一些改动。
There might be some bugs with it but it is only a prototype so you can edit and makes that look better of course.
它可能存在一些错误,但它只是一个原型,因此您当然可以编辑并使其看起来更好。
For some reason I didn't success to make the dropdownlist
to be clickable. It seems like z-index issue or other css properties games. I trust on you to find how to fix it.
Anyway for now, you can use the keyboard to select by holding shift for multiple selection.
出于某种原因,我没有成功使dropdownlist
可点击。这似乎是 z-index 问题或其他 css 属性游戏。我相信你会找到解决方法。无论如何,您现在可以使用键盘通过按住 shift 进行多选来进行选择。
The output is a collection of joined selected options by comma separated.
输出是由逗号分隔的连接选定选项的集合。
for example:
例如:
To make that work add this code after you load handsontable libary. It will extend your Handsontable
cell types.
为了完成这项工作,请在加载 handsontable 库后添加此代码。它将扩展您的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's 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);
The way to use it:
使用方法:
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
} {}]
});
Live demo in here
现场演示在这里
To make it easy on you. If you want to edit the code there are 2 methods you may want to change.
为了让你轻松。如果您想编辑代码,您可能需要更改两种方法。
prepare
- Will be called every time the user triggered an editor open event. For configurations and manipulations.init
- That method will be called every time you click on a cell. It creates the html code so you can change it to checkboxes for example.
prepare
- 每次用户触发编辑器打开事件时都会调用。用于配置和操作。init
- 每次单击单元格时都会调用该方法。例如,它会创建 html 代码,因此您可以将其更改为复选框。
Another thing relates to your questions about where things in the code.
另一件事与您关于代码中内容的问题有关。
Handsontable split any cell type to editor and renders.
All the html code of the editor probably exists in the init
in case that you want to change one of them.
The value
which is the html content that appears in the cell when you are notin edit mode exists in getValue
method.
Handsontable 将任何单元格类型拆分为编辑器并呈现。init
如果您想更改其中之一,则编辑器的所有 html 代码可能都存在。的value
是,当你出现在单元格中的HTML内容无法在编辑模式下存在的getValue
方法。
I hope it helps, and I hope it fits to your current version.
我希望它有所帮助,我希望它适合您当前的版本。