Problem
The script currently shows a brief Flash of Unstyled Content (FOUC) because you're tapping into the shown event which, according to the Bootstrap Modal Events:
show.bs.modal
is fired when the modal has been made visible to the user
(will wait for CSS transitions to complete).
The only reason it appears to work after the first try, is because the position()
function will leave the position as part of the markup
So this:
<!-- language: lang-html -->
<div class="modal" >
Will become this:
<!-- language: lang-html -->
<div class="modal" style="top: 34px; left: 104px;" >
And it will pick up where it left off and then attempt to reposition. However, this is only good when the modal doesn't need to change between requests.
Solution - Part 1
Instead, of waiting until it's rendered, you need to tap into the show.bs.modal
event which will fire before the element is shown and reposition at this time.
The rub, is that at this moment in time, the modal is hidden, and according to the documentation on jQuery UI - Position:
jQuery UI does not support positioning hidden elements.
Solution - Part 2
As a workaround, according to this Stack Overflow question on jQuery ui positioning keep changing, you can style the modal as an invisible block to help in calculating position:
<!-- language: lang-css -->
.modal {
display: none,
visibility: visible
}
Solution - Part 3
Additionally, there's no need to re-attach the .on()
listener for every click of the button. That initialization should happen in the beginning and then rely on the event handling to call the correct method. This does introduce the additional problem that you can no longer pass the button into the event handler through the function scope.
So instead you need to add the calling button to the modal as a data parameter like this:
<!-- language: lang-js -->
$('#MyModalWindow').data("source", $(this))
So you can read it in the event handling like this:
<!-- language: lang-js -->
.position({
my: 'left top',
at: 'right bottom',
of: $(this).data("source")
})
Here's a demo in Stack Snippets
<!-- begin snippet: js hide: false -->
<!-- language: lang-js -->
$('#MyModalWindow').on('show.bs.modal', function(e) {
$(this)
.css({
'display': 'block',
'visibility': 'hidden'
})
.position({
my: 'left top',
at: 'right bottom',
of: $(this).data("source")
})
.css({
'visibility': 'visible'
});
})
$('.my-element').click(function(){
$('#MyModalWindow')
.data("source", $(this))
.modal();
});
<!-- language: lang-css -->
.modal-backdrop.modal-backdrop {
background-color: transparent
}
<!-- language: lang-html -->
<link href="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/css/bootstrap.css" rel="stylesheet"/>
<script src="//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.2/js/bootstrap.js"></script>
<button type="button" class="btn btn-primary my-element" >
Open modal
</button><br/><br/>
<button type="button" class="btn btn-primary my-element">
Open modal
</button>
<div class="modal fade" tabindex="-1" role="dialog" id="MyModalWindow" >
<div class="modal-dialog modal-sm">
<div class="modal-content">
<div class="modal-body">
Modal Content
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">
Close
</button>
</div>
</div>
</div>
</div>
<!-- end snippet -->