Custom editor event propagation

I am creating some custom editors using angular and in particular I am using a ui-select inside a panel. So far so good, except I am not understanding how to stop hot-table from using events until my editor decides to.

I saw in the selectEditor that you could addHook to onBeforeKeyDown and such, but this is already handled by ui-select. I just need those events not to be handled by handontable until the editor is closed.

Any help appreciated

Thanks

Hi @pdemilly unfortunately I didn’t had an opportunity to use ui-select but I think that you can try to publish the same question on Stackoverflow. Currently it’s one of best places for developers to share mix-libraries examples.

Regardless of ui-select, how can I stop mouseEvent to be interpreted by handsontable. In my custom editor I present a list in a panel that spans multiple row. When the user click an item on the list the mouse event is first seen by handsontable. The stacktrace shows:

BaseEditor.finishingEditing
EditManager.closeEditor
EditManager.destroyEditor
Core,Selection.selection.deselect
Corre.deselectCell
(anoymous function) which translates to

event = extendEvent(context, event);
callback.call(this, event);
}

Of addEventListener. So I should somehow tell handsontable not to interpret those mouse event. If I add an addEventListener for mousedown where should I set it and restore it. In Open and close. And what should I set it to?

Thanks

Pascal

Right now I do this

   var stopEvent = function (event) {
            $log.debug ('>>> got event: ', event);
            var ct = self.compiledTemplate[0];
            if (lodash.findIndex (event.path, function (it) { return it.classList.contains('ui-select-container'); } ) > 0) {
                    $log.debug ('>>>> STOP PROPAGATING');
                    event.stopImmediatePropagation();
                    event.preventDefault ();
            }
    };

    self.prototype.open = function() {
            .......
            var eventManager = Handsontable.eventManager(this);
            eventManager.addEventListener(this.instance.rootElement, 'mousedown', stopEvent)
     }

However it is closing the editor. I need to tell handsontable to disregard mousedown events (I assume that is what makes it close the editor). I think it is my stopImmediatePropagation that is wrong. It is only for that event, when I need to tell handsontable to ignore any further mousedown.

Any help appreciated

I found in handsontable where the eventListener is set. Line 19165 of handsontable-pro v1.2.0. Since ui-select-container is not part of handsontable DOM tree structure, handsontable looks at it as being an outside mouseDown event and decide to either deSelect the cell or destroy the editor.

this.eventManager.addEventListener(document.documentElement, 'mousedown', function(event) {
    var next = event.target;
    var eventX = event.x || event.clientX;
    var eventY = event.y || event.clientY;
    if (isMouseDown || !instance.rootElement) {
      return;
    }
    if (next === instance.view.wt.wtTable.holder) {
      var scrollbarWidth = getScrollbarWidth();
      if (document.elementFromPoint(eventX + scrollbarWidth, eventY) !== instance.view.wt.wtTable.holder || document.elementFromPoint(eventX, eventY + scrollbarWidth) !== instance.view.wt.wtTable.holder) {
        return;
      }
    } else {
      while (next !== document.documentElement) {
        if (next === null) {
          if (event.isTargetWebComponent) {
            break;
          }
          return;
        }
        if (next === instance.rootElement) {
          return;
        }
        next = next.parentNode;
      }
    }
    if (that.settings.outsideClickDeselects) {
      instance.deselectCell();
    } else {
      instance.destroyEditor();
    }
  });

Then it goes to this.selection.deselect which destroy the editor.

deselect: function() {
      if (!selection.isSelected()) {
        return;
      }
      instance.selection.inProgress = false;
      priv.selRange = null;
      instance.view.wt.selections.current.clear();
      instance.view.wt.selections.area.clear();
      if (priv.settings.currentRowClassName || priv.settings.currentColClassName) {
        instance.view.wt.selections.highlight.clear();
      }
      editorManager.destroyEditor();
      selection.refreshBorders();
      Handsontable.hooks.run(instance, 'afterDeselect');
    },

So my question is how can I prevent handsontable to destroy my editor (kind of like a modal would do).

Thanks

Pascal

By the way while browsing the code I can see that defineProperty is misspelled at few places in the code

8723 ($traceurRuntime.createClass)(EventManager, {
 8724   addEventListener: function(element, eventName, callback) {
 8725     var $__3 = this;
 8726     var context = this.context;
 8727     function callbackProxy(event) {
 8728       if (event.target == void 0 && event.srcElement != void 0) {
 8729         if (event.**definePoperty**) {
 8730           event.**definePoperty**('target', {value: event.srcElement});
 8731         } else { 
 8732           event.target = event.srcElement;
 8733         }
 8734       }
 8735       if (event.preventDefault == void 0) {
 8736         if (event.**definePoperty**) {
 8737           event.**definePoperty**('preventDefault', {value: function() {
 8738               this.returnValue = false;
 8739             }});
 8740         } else {
 8741           event.preventDefault = function() {
 8742             this.returnValue = false;
 8743           };
 8744         }
 8745       }
 8746       event = extendEvent(context, event);
 8747       callback.call(this, event);
 8748     }
 8749     this.context.eventListeners.push({
 8750       element: element,
 8751       event: eventName,
 8752       callback: callback,
 8753       callbackProxy: callbackProxy
 8754     });
 8755     if (window.addEventListener) {
 8756       element.addEventListener(eventName, callbackProxy, false);
 8757     } else {
 8758       element.attachEvent('on' + eventName, callbackProxy);
 8759     }
 8760     Handsontable.countEventManagerListeners++;
 8761     return (function() {
 8762       $__3.removeEventListener(element, eventName, callback);
 8763     });
 8764   },

I found a solution to my problem. In the open function of the editor, I call add an event listener directly to the document.documentElement in capturing more (last argument = true)

        document.documentElement.addEventListener('mousedown', stopEvent, true);
        documentMouseDownListener = function () {
                document.documentElement.removeEventListener ('mousedown', stopEvent, true);
        };

and in stopEvent, I just cancel event propagation.

var stopEvent = function (event) {
event.stopImmediatePropagation();
event.preventDefault ();
};

However I am afraid that won’t work in all browsers (capturing vs bubbling of events). I would expect handsontable to have the ability to declare an editor modal.

Now to my next problem, I would expect that after an editor is close, that the renderer if defined is called. However it is not. The model returned by my editors is complex (object) and I want my renderer to just display a string representation of it.

Any feedback appreciated.

Hi @pdemilly I see than you’ve made a huge progress in this case. If you could ask me exactly what behavior you’re expecting I’d be happy to help.

I am trying to use handsontable at a bulk data entry widget. For this I need to have the ability to create custom editors for each type of cells. Some cells might be composite objects and the associated editor might have multiple fields. The custom renderer should accommodate and display a string representation of that object. My first step was to create a custom editor where the templates can be an angular template as this is what I used. My second step (which is where I was at the beginning of the thread) was to make sure that any events, mousedown, keydown and such were not interpreted by handsontable but left to my editor. Following what I did, you should now be able to create modal custom editor to handsontable. (I would like some feedback on what I did: document.documentElement.addEventListener(‘mousedown’, stopEvent, true); as it is more a hack than anything else. Maybe handsontable should give us the ability to specify that the editor is in modal mode. My 3rd step is going to have work with complex objects. Right now I have to return a JSON string to work. I would like my custom editor to return a complex object and have handsontable just save it to my model and pass it to my custom renderer.

Also I will open a github issue about the event.definePoperty error

Thanks

Hi @pdemilly sorry for a delay. I wasn’t notified with this update.
When it comes to editors in the end of March - beginning of April we will be releasing refactored editors and some of issue will be gone.