survey-library
survey-library copied to clipboard
Animated page transitions
Are you requesting a feature, reporting a bug or asking a question?
Feature
I'm working on animating page transitions but am running into some issues that make the solution quite hacky.

What is the current behavior?
The event to detect a page change even is onCurrentPageChanging. After that returns the element is immediately removed from the DOM, meaning any animations won't show.
What I do now when the event triggers is:
- Add a CSS class to trigger the animation.
- Prevent the page change (
options.allowChange) - Call
survey.nextPage()after a delay - Allow the page to change if the container already has the css class.
For the entrance transition, I store the direction we're moving in (important to make sure a slide-in occurs from the correct window side) and use that to add a CSS class in the onAfterRenderPage event.
What is the expected behavior?
Ideally the library would support animations a bit better by allowing us to control when elements get removed from the DOM.
Create a callback that can be used to hide the page container for example like this:
survey.hidePage = (htmlElement, cb) => {
// This code should hide the page, when it is done it should call `cb()` to notify SurveyJS that it may remove the element from the DOM.
// No animation:
cb();
// CSS Animation:
htmlElement.classList.add('fade-out-cool');
setTimeout(cb, 1000);
};
Fade-ins are inherently easier because we already have an event for elements that are added to the DOM.
Added benefit of my sample above is that it allows for some asynchronous behavior that can make the library appear smoother.
- Before removing the page we start the CSS animation.
- While the animation runs library code can already do the calculations required and therefore immediately load the next page when
cb()is called.
While my example uses callbacks, ofcourse anno ~ 2021 it probably makes more sense to use promises.
For example, hidePage could return a promise and when it resolves you remove the element:
survey.hidePage = (element) => {
element.classList.add('fade-out-cool');
return new Promise((resolve, reject) => {
setTimeout(resolve, 1000);
});
};
// Imaginary code:
...
async nextPageInternal() => {
if (!currentPage.validate()) {
return currentPage.highlightErrors();
}
// This is the existing event
trigger(beforeChanging);
if (!changeAllowed) {
// Exit early
return;
}
let element = getDOMElementForPage(currentPage);
let hidePage = survey.hidePage(element);
let nextPage = calculateNextPage();
let renderedElement = renderPage(nextPage);
await hidePage;
// Try to do heavy lifting before awaiting the promise
activateAndInsertIntoDOM(nextPage, renderedElement);
}
Would you be open to a PR for this?
Bump?
Hi there @SamMousa ,
Could you please share, how did you manage to do with your "hacky" way? :) I'm having some problems with my implementation.
Thx. ✌
To summarize my hacky way was:
- On first call to
onPageChangingstart animation, returnfalseso that page doesn't actually change. - After animation manually call
nextPage() - On second call return
true
I used Animate.css for the animations themselves.
Thx for your comment @SamMousa. I'm doing the same thing, even with the same library ( good old animate.css 🙂 ) But nextPage() triggers couple of times. I'm using React, maybe that is effecting. That means I'm missing something. Okay, I'll look into it, thx. 👍
Hi again @SamMousa, Are you having problems with "On answering all questions, go to the next page automatically" option as well? Because if I enable this option and click next page button after filling the question, it's skiping a page/question. Event fires 2 times.
I'm not using this in production since I found it too hacky. I remember something like this happened but am not sure how I fixed it.
Okay, at least you remember that you solved it somehow. So there is still hope. 🙂
@SamMousa hello,
I don't have much experience with CSS animations. For me, it is hard to understand what's going wrong here. Our example with the velocity-animate looks ok. And it also works with React. Here the example: https://codesandbox.io/s/survey-libraryissues2588-s434l?file=/src/SurveyComponent.jsx:343-359
If you created an example with animate.css it will probably help us to understand the problem. Thanks.
I don't have an example lying around at the moment and currently don't have time to spend on it.
@bakdakonusuruz I managed to prevent the skipping with checking for originalTarget.className == '{className}'
but as I'm using onAfterRenderQuestionInput, I have no luck with the css change