Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

onAfterChanges option (or something similar) #223

Open
StefanJelner opened this issue Feb 4, 2022 · 7 comments
Open

onAfterChanges option (or something similar) #223

StefanJelner opened this issue Feb 4, 2022 · 7 comments

Comments

@StefanJelner
Copy link

First of all thanks for this great library. I am using it for small reactive widgets in websites and it works like a charm.

In some scenarios i need to know, when morphing is completely finished. My approach now is to add onElUpdated, onNodeAdded and onNodeDiscarded and inside of the callbacks fire another callback which is throttled by request animation frame. This works for me, but is a little bit hacky in my opinion.

Would it be possible to provide an option - like onAfterChanges - which becomes invoked after everything has been done?

@pbowyer
Copy link

pbowyer commented Feb 9, 2022

I've had a need today for onAfterChanges to reorder the output, because nodes I prevent from being removed and newly inserted nodes end up in the wrong order (I can't change the HTML structure so have to fix in JS).

Adding this to morphdom would be very useful. In the meantime, are you able to share your working but hacky code?

@StefanJelner
Copy link
Author

StefanJelner commented Feb 10, 2022

Yes. Of course. What i do is to throttle all calls of onElUpdated, onNodeAdded and onNodeDiscarded. You can do this with the library raf-throttle to throttle it to the request animation frame or you can use something like throttle-debounce to do it by an amount of milliseconds.

Example:

import rafThrottle from 'raf-throttle';

const onAfterChanges = rafThrottle(() => console.log('onAfterChanges'));

morphdom(
    document.getElementById('foo'),
    '<div>bar</div>',
    {
        onElUpdated: () => onAfterChanges(),
        onNodeAdded: node => { onAfterChanges(); return node; },
        onNodeDiscarded: node => { onAfterChanges(); return node; }
    }
);

What happens is, that the throttled function onAfterChanges will get invoked again and again, but waits until nothing happens for a request animation frame. Then it will finally be invoked.

If you have further questions, feel free to ask. 😄

@snewcomer
Copy link
Collaborator

onAfterChanges I like the suggestion. I'd certainly be open for a PR. If one doesn't come across, I'll try and get to it this month.

@leastbad
Copy link

I'd love to see this implemented, so bump.

One thing that I'd strongly suggest is that such an "after" callback fire even if no changes are performed. We're currently dealing with the opposite situation eg. we need to run some cleanup after morphdom does its thing, but if nothing is changed then onElUpdated never runs.

@leastbad
Copy link

Building on @StefanJelner's solution - while acknowledging that I'm hoping for an outcome where a callback fires after processing even if there are no changes - is it fair and reasonable to say that a final call to onAfterChanges() immediately before line 753 would do the trick?

@StefanJelner
Copy link
Author

If onAfterChanges() gets the changes as an argument, then it is possible to decide, whether to do something or not, based on the content of the argument. F.ex. if the argument is an empty array, then it is clear, that actually nothing changed, while if it is an array of changes (how they look like might be another discussion), then i know that something changed. And maybe in some scenarios it is useful to know what exactly changed. Just my thoughts.

@leastbad
Copy link

I share your desire; it would be nice. In fact, I'm implementing a comparison concept in a library that uses morphdom right now.

Thing is, I would rather have morphdom be super fast than provide a changeset. I genuinely worry that making those changes available would require a lot more code and a lot more CPU cycles to run that code. (I'd be thrilled to be wrong.)

In our library, given that this functionality hasn't been merged and released yet, we're making use of the techniques discussed earlier in this thread - paired with an initial check where we compare the source fragment against the innerHTML of the target element. We figure that even if this is a heavy operation, it's still less heavy than calling morphdom if we know the source and target are already equal.

If this functionality does get merged down the line, we'll take that as an opportunity to simplify our local implementation by adopting the morphdom onAfterChanges event.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants