I have a backbonejs model-collection containing models for JSPlumb nodes (ID, parentIDs). The DOM representation is handled by React (divs with Endpoints). If I delete a model from the collection:
nodeCollection.remove(aNodeModel)
it gets removed from the DOM with all containing components - nice.
If I now add a new node, the Endpoint is not added. I tracked this issue down to some internals in JSPlumb: If I do a
jsPlumb.remove(aNodeModel.id)
the Endpoint-problem vanishes but I get a React "Invariant Violation" because the aNodeModel
was not removed from the nodeCollection.
If I remove the jsPlumb Endpoint manually before I remove the model from the collection:
jsPlumb.removeAllEndpoints(aNodeModel.id)
the problem remains.
This feels somehow like a deadlock... Any suggestions?
Open Source roxx.
I solved this problem by adding a parameter to the jsPlumb .remove() method controlling the actual DOM-deletion of the element inside jsPlumb. If I set this to false jsPlumb gets cleaned up nicely an I can let React delete the actual DOM-element after that:
jsPlumb.remove(sourceNodeID, false, [false])
This are the changes I did to the jsPlumb source in dom.jsPlumb-1.7.5.js, lines 5176 and 5210.
var _doRemove = function(info, affectedElements, removeDOMElement) {
_currentInstance.removeAllEndpoints(info.id, true, affectedElements);
var _one = function(_info) {
_currentInstance.getDragManager().elementRemoved(_info.id);
_currentInstance.anchorManager.clearFor(_info.id);
_currentInstance.anchorManager.removeFloatingConnection(_info.id);
delete _currentInstance.floatingConnections[_info.id];
delete managedElements[_info.id];
delete offsets[_info.id];
var actuallyRemoveDOMElement = true;
if (removeDOMElement.length > 0) {
actuallyRemoveDOMElement = removeDOMElement[0];
}
if (_info.el) {
if (actuallyRemoveDOMElement) {
_currentInstance.removeElement(_info.el);
}
_info.el._jsPlumb = null;
}
};
// remove all affected child elements
for (var ae = 1; ae < affectedElements.length; ae++) {
_one(affectedElements[ae]);
}
// and always remove the requested one from the dom.
_one(info);
};
/**
* Remove the given element, including cleaning up all endpoints registered for it.
* This is exposed in the public API but also used internally by jsPlumb when removing the
* element associated with a connection drag.
*/
this.remove = function (el, doNotRepaint, removeDOMElement) {
var info = _info(el), affectedElements = [];
if (info.text) {
info.el.parentNode.removeChild(info.el);
}
else if (info.id) {
_currentInstance.batch(function () {
_doRemove(info, affectedElements, removeDOMElement);
}, doNotRepaint === false);
}
return _currentInstance;
};