Dropdowns handstable avec plusieurs sélections

j'essaie d'étendre le plugin handsontable pour supporter plusieurs sélections dans sa liste déroulante. J'ai déjà essayé d'étendre l'éditeur de base construit dans la bibliothèque en modifiant le 'dropdownEditor' comme suggéré https://github.com/trebuchetty/Handsontable-select2-editor/issues/7. J'ai passé des heures à lire et à chercher des mots-clés dans la source, mais je ne trouve rien d'utile.

cela ne me dérange pas si on répond en utilisant le Extension angulaire ou une autre ECMA5 ou 6 façon d'étendre lehttps://github.com/handsontable/handsontable plugin.

jusqu'à présent, mes seules pensées étaient d'étendre le cadre avec ce peu de code en suivant les modèles qui existent. J'ai ajouté tous LOC, ci-dessous, pointant vers: multiselect ou Handsontable.MultiselectDropdownCell copié le dropdown méthode, appelée le nouveau nom et tout fonctionne, cependant, ne voyez toujours pas où je pourrais commencer à trouver ce que je cherche pour.

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
}};

j'ai une version modifiée de dropdown editor en place qui ressemble à:

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);

À ce stade, je n'ai aucune idée de où l'événement click se produit lorsque l'utilisateur sélectionne un élément dans la liste déroulante. Débogage a été douloureux pour moi parce que c'est à travers Traceur. J'ai essayé de définir un événement de clic après le module est prêt et le DOM est aussi bien, mais je ne peux pas obtenir même une alerte à tirer basé sur un clic sur l'un des dropdown select cellule. "Normal", les cellules que je peux obtenir un cliquer avec un simple:

$('body').on('click','#handsontable td', someAlert)

cependant, ce n'est pas le cas pour le contenu du menu. Clic droit pour inspecter le menu déroulant signifie d'abord désactiver le menu contextuel comme sur http://handsontable.com/. Ensuite, vous remarquerez que le clic droit d'inspecter tout va déclencher un événement qui ferme le menu déroulant, vous essayez de les inspecter.

j'ai mis des points de rupture dans toutes les bibliothèques source code, Je ne peux pas comprendre celui-là.

la seule chose que je veux faire est de comprendre où se trouve la partie du code qui met en évidence l'élément du menu et le place dans une sélection active, le transformer en une méthode qui accepte plusieurs sélections (jusqu'à l'ensemble des options disponibles, cliquer sur un élément actif le désactivera, disons).

puis s'assurer que ces sélections sont effectivement dans le Handsontable 'data scope'.

c'est ça, je n'ai pas besoin il même pour rendre dans la cellule ce que les choses ont été choisies, bien que n'importe quelle aide là-bas serait grande parce que malheureusement, je ne suis pas encore trouver l'endroit où les options dans le dropdown sont rendus soit.

j'ai aussi essayé D'utiliser le Select2Editor fait pour handsontable comme vu http://jsfiddle.net/4mpyhbjw/40/ et https://github.com/trebuchetty/Handsontable-select2-editor/issues/3, cependant cela n'aide pas beaucoup ma cause. Voici ce que l' liste déroulante de la cellule dans handsontable ressemble à:

http://docs.handsontable.com/0.15.1/demo-dropdown.html

Enfin, voici un violon: http://jsfiddle.net/tjrygch6/

je vous serais super reconnaissante si quelqu'un pouvait m'aider ici. Merci!

UPDATE

j'ai réussi à analyser les valeurs dans la cellule et tournez le type dans un tableau contenant les valeurs (donc en tapant rouge bleu va tourner un tableau contenant ['red','blue']). J'ai lancé ce tableau à travers l'algorithme de tri interne qui analyse les options et renvoie un index d'un élément correspondant. J'obtiens que cela fonctionne bien et je passe maintenant le tableau dans la méthode de surlignage. Cette méthode passe les valeurs de la bibliothèque de base WalkOnTable. Je ne vois pas où je peux modifier la logique pour sélectionner plus d'une valeur au lieu de décrocher la première option.

 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);
}

C'est la endroit où je pense que j'ai besoin WalkontableCellCoords à modifier pour accepter un tableau, puis mettre en surbrillance et sélectionner les deux valeurs lorsque la liste déroulante est ouverte et fermée. J'ai aussi besoin d'être capable de sélectionner plusieurs options via l'événement touch ou click.

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;

};

mise à Jour 2

j'ai obtenu les méthodes internes pour reconnaître et sélectionner partiellement les deux valeurs dans le DOM mais il est encore loin d'être correct.

Showing the selection (sort of) of both items based on two values typed into the cell, also showing the output in the console for the coord being returned from the WalkOnTable util being used behind the scenes in this handsontable plugin. Output is below

Voici la sortie de la console générés par la méthode WalkOnTableCellCords pour être appelé, ce qui semble être ce que souligne la liste déroulante de sélection dans le cas où la cellule ne contient que des 1 (valeur par défaut de la fonctionnalité). Cette sortie est de dactylographier le bleu noir dans une cellule de descente contenant à la fois le bleu et le noir comme options individuelles dans la liste.

extended_hot_v15-01.js:5041 DropdownEditor {
            "highlight": {
                    "row": 6,
                    "col": 0
            },
            "from":
                   {
                    "row": 4,
                    "col": 0
                   },
             "to": {
                    "row": 6,
                    "col": 0
                    }
            }

UPDATE si quelqu'un résout cela, je le ferai volez personnellement à l'endroit où vous êtes en personne, et serrez votre main. À deux reprises.

18
demandé sur YakovL 2015-08-11 03:37:42

2 réponses

Wow. Tant d'efforts. Maintenant, plus d'un an plus tard, il est beaucoup plus facile.

j'ai utilisé le plugin jQuery choisi avec succès. C'était assez facile.

Voici l'exemple d'une personne: https://github.com/mydea/handsontable-chosen-editor

choisi est beau. J'utilise autocomplete avec un multi-select. Voici le rendu:

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;
}

et puis je viens de mettre en place la colonne particulière comme ceci:

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
répondu Rolok 2017-06-04 10:38:47

Ok, j'espère que ça va vous aider. Il m'a fallu le temps de lire l'api et de personnaliser le code :)

j'ai pris un exemple de code à partir de Handsontable bibliothèque (dernière version) et fait peu de changements.

il y a peut-être des bugs, mais ce n'est qu'un prototype, donc vous pouvez éditer et rendre cela plus visible bien sûr.

Pour une raison que je n'ai pas de succès pour faire de l' dropdownlist pour être cliquable. Il semble comme l'édition de z-index ou d'autres jeux de propriétés css. J'ai confiance sur vous pour trouver comment corriger le problème. De toute façon pour l'instant, vous pouvez utiliser le clavier pour sélectionner en tenant Maj pour la sélection multiple.

la sortie est une collection d'options sélectionnées jointes par virgule séparée.

par exemple:

enter image description here enter image description here

pour que cela fonctionne, ajoutez ce code après avoir chargé handsontable libary. Il permettra de prolonger votre Handsontable types de cellules.

(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);

le chemin vers utiliser:

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
    } {}]
});

démonstration ici

Pour le rendre facile sur vous. Si vous souhaitez modifier le code il y a 2 méthodes que vous souhaitez modifier.

  1. prepare - sera appelé à chaque fois que l'Utilisateur a déclenché un événement Open editor. Pour configurations et manipulations.

une autre chose se rapporte à vos questions sur l'endroit où les choses dans le code.

Handsontable split importe quel type de cellule à l'éditeur et les restitue. Tout le code html de l'éditeur existe probablement dans le init au cas où vous voudriez en changer un. value qui est le contenu html qui apparaît dans la cellule quand vous êtes en mode édition existe en getValue méthode.

j'espère que cela aide, et j'espère qu'il s'adapte à votre version actuelle.

4
répondu Dvir 2015-11-09 14:11:01