Following the feature request #17800, the PR #17823 has been merged.
It prompted several issues with the error message Error: <Component> is transitioning
in the browser console of the user.
This ticket aims at centralizing those issues, gather feedback and discuss a possible solution.
Here is the issues found so far:
The issue #21687 has also been reported but it's not directly related. See comment
The original feature request and PR attempt to warn the user when he call the component API repeatedly instead of waiting for and even before making the next call.
Even though this behavior is expected and documented. See comment
It worth noting that the previous behavior (skip the call if it's transitioning) is quite common and most framework works this way and expect the developer to understand the notion of asynchronous.
Unfortunately, with the current implementation (#17823) it seems we have inadvertently created more problems than we solved... In addition we have added some complexity to the code, and it seems difficult to anticipate all the potential problem that will be found.
Here is a few solutions I can think of.
$().modal
start 2 successive transitions (backdrop then the modal itself. It would require to distinguish which transition is on going and react differently.Feel free to propose and discuss other potential solutions.
My hunch is that solution 1 (revert and document) might be better. The problem we try to solve is related to developers who do not read the docs or understand asynchronous functions. It feels like this issue is better solved by improved documentation, especially when the "code solution" create issues for the end user.
And I think the doc can be improved in that regard.
The problem I see with the "code solution" is that it will either create a constant source of bugs or become extremely complicated in order to handle every possible case. Not mentioning that it would make adding new modules/feature more complicated.
I'd love to hear the community and bootstrap team ideas/feedback/opinion.
Thanks @vanduynslagerp - I've considered making such an issue as yours, as we've seem to have found a pattern of issues here.
I've been absent in my issue (#21600) but I've been working towards a fix for myself (my approach is along your first solution - I'm reverting a lot of #17823 with good luck so far.) I believe this added complexity is preventing parent-stack execution and in some cases (#21600) is breaking the user interface - a critical problem for a UX/UI library.
I don't think we need to put any warnings in the documentation because mid-transitions should be, and could be, handled by Bootstrap internally. If a developer calls code inefficiently (#17796) then they should still get what they expect. I'm still familiarizing myself with v4's current source code, but it will be possible to gracefully handle back-to-back transitions. Luckily we're in alpha, right?
Thanks again for consolidating all of our issues with yours!
@vanduynslagerp Huge thanks for collating all this. Assigning this to myself so I remember to work through this tomorrow. If anyone else wants to take it, feel free.
I made the PR which created all this issues but like @vanduynslagerp I prefer the first option because finally it's a developer problem not a user's problem
@METACEO,
If a developer calls code inefficiently (#17796) then they should still get what they expect.
The code in #17796 is not inefficient, it's just wrong for what the developer want to do (presumably open a modal, then when it's opened, close it, then when it's closed, open it again) because the methods are asynchronous.
I propose to mentioned that more clearly in the docs, because if a developer think he will obtain the expected result by writing the code #17796 it means he ignore that these methods are asynchronous.
If it's actually what he expect the only solution to make that work is to create an internal queuing mechanism. Or make the methods synchronous.
I think this is what you are referring to here:
it will be possible to gracefully handle back-to-back transitions
Making the methods synchronous is obviously an anti-pattern in Javascript.
Building an internal queuing would be extremely complicated and I think would not produce the results expected by the end user.
Let's imagine a collapsible area that can be shown/hidden by a button. The css transition-duration
on the collapsible area is set to .5s
.
Now the user click 6 time very fast on the button.
Does he want to queue the showing and hiding transition and run them ? and ending with the collapse opening and closing 3 times, back to back during 3 seconds ?
Or does he want his last action to be taken immediately, cancelling the previous one ?
All the Bootstrap modules are designed to handle user actions on the UI. I think the user expect them to be immediate. If the user decide to expand a collapsible area, that takes .5s to expand, and after .25s changes his mind and closes it, he expect the close action to be taken right away, by cancelling the opening animation and start the close one right away.
This was the behavior before #17823.
@vanduynslagerp - the underlying problem here is how to handle elements mid-transition. I do not mean to imply synchronous methods or some sort of internal queue. This is what I see when I look at code such as #17796:
$('#myModal').modal('show'); // Transition the backdrop and modal to view.
$('#myModal').modal('hide'); // Stop previous transitions and transition the backdrop and modal out of view.
$('#myModal').modal('show'); // Stop previous transitions and transition the backdrop and modal to view.
$('#myModal').modal('hide'); // Stop previous transitions and transition the backdrop and modal out of view.
With these calls being asynchronous, we expect the backdrop and modal to remain hidden after the above has executed. So I am agreeing with you here:
I think the user expect them to be immediate. If the user decide to expand a collapsible area, that takes .5s to expand, and after .25s changes his mind and closes it, he expect the close action to be taken right away, by cancelling the opening animation and start the close one right away.
It would be ridiculous to see #17796's code in production, I think we'd agree, but if we just call this wrong and throw errors then Bootstrap's users will need to be educated and warned.
I think we can avoid further education if we work to keep Bootstrap's API intuitive - that includes limiting the amount of thrown errors and solving problems with the least amount of additional "Do's & Do Not's" in the documentation.
I'm not against informative documentation, but Bootstrap can handle transitions without the user's concern.
I think before #17823 the behavior was what you describe here:
$('#myModal').modal('show'); // Transition the backdrop and modal to view. $('#myModal').modal('hide'); // Stop previous transitions and transition the backdrop and modal out of view. $('#myModal').modal('show'); // Stop previous transitions and transition the backdrop and modal to view. $('#myModal').modal('hide'); // Stop previous transitions and transition the backdrop and modal out of view.
Wasn't it ?
Anyway, we are on the page: Starting a transition during another one should stop the first one and execute the second one immediately. :-)
I don't know about before #17823, I've recently been getting my feet wet with v4 and I'm reviewing its source for both this issue and my own fix.
@cvrebert what are your insights regarding this issue?.. including your experiences with #17796, #17800 w/others, and #18287.
After spending some time on this issue I came up with a third solution (I updated the initial comment) but it seems quite difficult to implement. My attempt can be found here.
I went ahead with solution 1 here #21743. After hours noodling on the different possibilities, I think it's the best solution.
@Johann-S this isn't a developer problem or a users problem. Its a problem you created...
Out of the box, this happens to me. All I'm literally doing is adding a tooltip to an element... I wish there was a real solution.
Yes I know thank you @jaketoolson 馃憤
But I was talking about handling element transition that's why it's a developer problem not a user one.
I have the same issue when showing tooltips on elements in a variable sidenav which shows when window is resized to small viewport sizes.
Is there a way to just ditch the transitions if it makes such a huge problem?
In my mind they are bonus but not needed. If my tooltips don't show at all any more I'd rather not have any fancy "transitions" which shoot me in the foot.
Transitions aren't the problem here. Always going nuclear is.
You know, this whole thing looks a lot like Ember.js's famous/notorious "calling set on destroyed object" error, where Ember.js would assume end of the world scenario happened and errored because you've tried to change state of object that was in gc queue. On other side, React.js authors who encountered same situation assumed that most of time that such scenario occurs, there's likely no risk of real error happening anyway, and opted for warning instead. So React.js warns you with "hey, component that you've unmounted tried to change its state, see if this is an issue" when you are in dev builds, and stays quiet in prod builds.
I believe that attempting other transition within current transition should simply raise warning and don't perform any new transition at all. In addition I would like more explicit callback API's for those transitions, like such:
$('#muh-modal').modal('show', () => {
this.setState({ isVisible: true });
});
Even without including fade
with modal
, when I run $("#"+id).modal('hide');
from the console on a clearly visible modal, I'll receive the Tooltip is transitioning
for tooltips within the modal, which prevents the modal from closing. Is there a recommended hotfix to force
hide the modal or something along those lines?
In case others need it, this is my hotfix for modals, assuming id is the modal's id.
var that = $("#"+id);
$("body").removeClass("modal-open");
$("body").css({"padding-right": "0"});
that.removeClass("show");
that.css({"display": "none"});
$(".modal-backdrop").remove();
var bsModal = that.data('bs.modal');
bsModal["_isShown"] = false;
bsModal["_isTransitioning"] = false;
that.data('bs.modal', bsModal);
Found another 'Modal is transitioning' bug which happens if you .modal('hide')
an already hidden modal. Then, it gets stuck in that "transitioning" state until page refresh or applying fix above.
Example code:
$('.modal').each(function() { $(this).modal('hide'); });
If you run it, it will hide every modal on the page, causing them to get bugged.
I can confirm @tmp64 his cause. I had some code from BS3, transitioning (no pun intended) to 4 and ran into the issue. If you hide a modal before it's shown, and then toggle / show it - you get the error! Hope it helps.
I've personally reverted this feature in my environment, on carousels only, as I need it to go into "production ready code." This is just my opinion but it seems that this feature has added unnecessary complexity. Allowing users to skip an item in transition, in regards to carousels, can be a valid use case. Impatient users, users quickly fumbling through large carousels, etc, seems like a valid use case to me. Again I did this in my environment only, as we really want to upgrade to v4, but reverting the feature allows the carousel to work in a manner that is similar to v3.
Carousel.prototype.next = function next() {
this._slide(Direction.NEXT);
};
Carousel.prototype.prev = function prev() {
this._slide(Direction.PREVIOUS);
};
This issue also occurs on modals when they are non-stacking events with no other associated components firing.
This issue is the most terrible moment that I have ever had with Bootstrap. In case when you should have a lot of modals on an one page and they should openclosed via sequence it's just horrible in case if the transition can't be aborted automatically when a new transition launches.
This issue happens with any JavaScript component, not just with modal. Through SASS I'm only enabling scss/popover for transitional effects and still see this error in the console.
Bootstrap4
This is what worked for me.
npm i --save [email protected]
npm i --save popper.js@^1.12.3
<script src="node_modules/popper.js/dist/umd/popper.js"></script>
<script src="node_modules/bootstrap/dist/js/bootstrap.js"></script>
Good Luck...
Thanks @pjdufour this worked for me, the only thing is that the ESC key does not work, but with this I can hide the modal
function hideModal() {
var that = $("#idMyModal");
$("body").removeClass("modal-open");
$("body").css({"padding-right": "0"});
that.removeClass("show");
that.css({"display": "none"});
$(".modal-backdrop").remove();
var bsModal = that.data('bs.modal');
bsModal["_isShown"] = false;
bsModal["_isTransitioning"] = false;
that.data('bs.modal', bsModal);
}
v4.0-dev
modal.modal('show').on('shown.bs.modal', function (e) {
content_body.empty().html('Are you sure?')
// console.log(modal.data('bs.modal'))
}).on('hidden.bs.modal', function (e) {
content_body.empty()
}).on('click', '.btn-primary', function (e) {
$.post(ajax_url, {
action: 'del',
id: id
}).done(function (res, status) {
if ( res.success ) {
var sync = modal.find('.btn-secondary').trigger('click')
$.when( sync ).then(function () {
tr_target.fadeOut(500, function() {
this.remove()
})
})
} else {
content_body.empty().html('<span style="color:red">'+res.data+'</span>')
}
})
})
well done for me.
Most helpful comment
This issue is the most terrible moment that I have ever had with Bootstrap. In case when you should have a lot of modals on an one page and they should openclosed via sequence it's just horrible in case if the transition can't be aborted automatically when a new transition launches.