canjs / can-stache-animate

Animations and How-Tos for Animating in Stache
https://www.npmjs.com/package/can-stache-animate
MIT License
1 stars 1 forks source link

Handle $removed #9

Closed mickmcgrath13 closed 7 years ago

mickmcgrath13 commented 7 years ago

When the $removed event happens, we need to do an animation prior to its being removed from the DOM. This was handled in the old can-animate via overriding can.remove:

import can from "can";

can.oldRemove = can.remove;
// wrap the remove function
can.remove = function (wrapped) {
  // console.log("can.remove");
  var preventDefault = false;

  can.each(wrapped, val => {
    if (val.nodeType === 1) {
      var v = $(val),
        before;
      if (before = can.data(v, '_beforeRemove')) {
        preventDefault = true;
        before(() => can.oldRemove.apply(this, [val]));
      }
    }
  });

  if (preventDefault) {
    return wrapped;
  }

  return can.oldRemove.apply(this, arguments);
};

..the rub is that in the old can-animate, we used a can-view-attr (can-animate), and we knew exactly which elements on which to add the _beforeRemove data. With can-stache-animate, however, it isn't clear which elements might want to call $removed unless we hook into can-stach-bindings or something?

Thoughts: We could add a $beforeRemoved event, but 1) that'd be pretty heavy and mostly unnecessary (it'll probably be a small percentage of elements in an app that would utilize $beforeRemoved, and 2) it'd have to be a weird sort of event that allows the delaying of the actual removal (promise?).

...or... We could hook into can-stache-bindings and add a similar _beforeRemoved data property? ..not sure how that'd work, though...

This issue needs a discussion.

mickmcgrath13 commented 7 years ago

More thoughts: What if, in can-stache-bindings, we check for a $beforeremove event. If it exists, add a beforeremove data property on the element that is set to the event's handler. Then, execute that function prior to removal, and if the result of that function is a promise, wait until it resolves before actually removing the element?

in can-stache-bindings, this:

canEvent.on.call(context, event, handler);

..would change to something like this:

var bindFunc;
if(onBindElement && event === "beforeremove"){
  bindFunc = domData.set;
}else{
  bindFunc = canEvent.on;
}
bindFunc.call(context, event, handler);

In can-view-nodelist, this:

    remove: function(elementsToBeRemoved){
        var parent = elementsToBeRemoved[0] && elementsToBeRemoved[0].parentNode;
        each(elementsToBeRemoved, function(child){
            domMutate.removeChild.call(parent, child);
        });
    },

..would change to something like this:

remove: function(elementsToBeRemoved){
  var parent = elementsToBeRemoved[0] && elementsToBeRemoved[0].parentNode;
  each(elementsToBeRemoved, function(child){
    var remove = function(){
          domMutate.removeChild.call(parent, child);
        },
        beforeRemove = domData.get.call(child, 'beforeremove'),
        beforeRemoveResult;
    if(isFunction(beforeRemove)){
      beforeRemoveResult = beforeRemove(); //.call?  what should be the context/params?
      if(isPromiseLike(beforeRemoveResult)){
        beforeRemoveResult.then(function(){
          remove();
        });
      }else{
        remove();
      }
    }else{
      remove();
    }
  });
},

..I've tested this locally, and it seems to work

mickmcgrath13 commented 7 years ago

I wonder if the above implementation would have any impact on can-control?