Bootstrap 3 modal: make it movable/draggable without jquery-ui

Viewed 9704

I'm tring to develop some things:

  • make a bootstrap modal draggable/movable on the window without jquery-ui

I use backbone.js but I think this is not so important. In a piece of code I define my bootstram modal:

<div id="detailsContainer">
<div class="modal fade" id="someId" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
    <div class="modal-content">
        <div class="modal-header">
            <button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">&times;</span></button>
            <h4 class="modal-title" id="myModalLabel"><span class="glyphicon glyphicon-cloud-upload" aria-hidden="true"></span> Some Title</h4>
        </div>
        <div class="modal-body" id="content">

            <form class="form-horizontal" role="form" id="modalFormBody">
                ... some content
            </form>    

        </div>
        <div class="modal-footer">
            <div class="pull-right" id="modalButtonBar">
                <button type="button" class="btn btn-default control-button" data-dismiss="modal">Close</button>
                <button type="button" class="btn btn-primary control-button" id="addButton">Add</button>
            </div>                  
        </div>
    </div>
</div>

Now when I try to use set the modal draggable with this code:

 var $container = $("#detailsContainer");
 $container.on('mousedown', 'div', function() {
            $(this).addClass('draggable').parents().on('mousemove', function(e) {
                $('.draggable').offset({
                    top: e.pageY - $('.draggable').outerHeight() / 2,
                    left: e.pageX - $('.draggable').outerWidth() / 2
                }).on('mouseup', function() {
                    $(this).removeClass('draggable');
                });
            });
            e.preventDefault();
        }).on('mouseup', function() {
            $('.draggable').removeClass('draggable');
        });

the behaviour is strange:

  • when I pick up the modal the modal goes out of window. I tried to fix changing some values to top and left, but nothing has been good.
  • when I pick some under element of the modal-body (for example an Input text), then I can move arround in the modal the input text. But I don't want this! I only want that the whole modal can be draggable/movable.

The example above I have found it on stackoverflow (Sorry I don't find the link on it). I find also some example with jquery-ui. But I don't want to use it. Only Jquery.

I have also tried: Dialog draggable, and JQuery Draggable Demo. But without success. The first one don't make my modal draggable, and the second one I din't understand how to use it with $container

Can someone help me?

Update

        $('body').on('mousedown', '.modal-dialog', function() {
             $(this).addClass('draggable').parents().on('mousemove', function(e) {
                 $('.draggable').offset({
                     top: e.pageY - $('.draggable').outerHeight() / 2,
                     left: e.pageX - $('.draggable').outerWidth() / 2
                 }).on('mouseup', function() {
                     $(this).removeClass('draggable');
                 });
             });
             e.preventDefault();
         }).on('mouseup', function() {
             $('.draggable').removeClass('draggable');
         });

But when I want to drag... it changes the position of where I picked it up the modal. It goes on the corner. Not there where I picked it up? How can I correct this? It's wrong to put the ".modal-dialog" on the mousedown function? And If this is wrong, which element I have to put it there?

And an other point: the elements that I have in the modal body (example drop down) must not be draggable. How can I exclude them?

2 Answers

This answer is too late, but in case someone (like me) was searching for a solution to this. Finally, my solution was to use this code:

(function ($) {
    $.fn.drags = function (opt) {

        opt = $.extend({ handle: "", cursor: "move" }, opt);

        var $el = null;
        if (opt.handle === "") {
            $el = this;
        } else {
            $el = this.find(opt.handle);
        }

        return $el.css('cursor', opt.cursor).on("mousedown", function (e) {
            var $drag = null;
            if (opt.handle === "") {
                $drag = $(this).parents('.modal-dialog').addClass('draggable');
            } else {
                $drag = $(this).parents('.modal-dialog').addClass('active-handle').parent().addClass('draggable');
            }
            var z_idx = $drag.css('z-index'),
                drg_h = $drag.outerHeight(),
                drg_w = $drag.outerWidth(),
                pos_y = $drag.offset().top + drg_h - e.pageY,
                pos_x = $drag.offset().left + drg_w - e.pageX;
            $drag.css('z-index', 1000).parents().on("mousemove", function (e) {
                $('.draggable').offset({
                    top: e.pageY + pos_y - drg_h,
                    left: e.pageX + pos_x - drg_w
                }).on("mouseup", function () {
                    $(this).removeClass('draggable').css('z-index', z_idx);
                });
            });
            e.preventDefault(); // disable selection
        }).on("mouseup", function () {
            if (opt.handle === "") {
                $(this).removeClass('draggable');
            } else {
                $(this).removeClass('active-handle').parent().removeClass('draggable');
            }
        });

    }
})(jQuery);

Then, when the modal is shown:

            $('#modal').on('shown.bs.modal', function () {
                $(this).find('.card-header').drags();
            });

            $('#modal').modal({ show: true, backdrop: 'static', keyboard: false });

I am using a card inside the modal dialog with an HTML like this:

<div id="modal" class="modal fade">
    <div class="modal-dialog modal-dialog-centered modal-lg">
        <div class="modal-content  animated bounceInRight">
            <div class="modal-body">
                <div class="card">
                    <div class="card-header border-bottom-0">My super title</div>
                    <div class="card-body">
                        <form >...</form>
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="submit" class="btn btn-success" id="btnAlmacenar"><i class="fa fa-save"></i> Almacenar</button>
                <button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-close"></i> Cancelar</button>
            </div>
        </div>
    </div>
</div>

This is the whole snippet if you want to try it:

(function ($) {
        $.fn.drags = function (opt) {
    
            opt = $.extend({ handle: "", cursor: "move" }, opt);
    
            var $el = null;
            if (opt.handle === "") {
                $el = this;
            } else {
                $el = this.find(opt.handle);
            }
    
            return $el.css('cursor', opt.cursor).on("mousedown", function (e) {
                var $drag = null;
                if (opt.handle === "") {
                    $drag = $(this).parents('.modal-dialog').addClass('draggable');
                } else {
                    $drag = $(this).parents('.modal-dialog').addClass('active-handle').parent().addClass('draggable');
                }
                var z_idx = $drag.css('z-index'),
                    drg_h = $drag.outerHeight(),
                    drg_w = $drag.outerWidth(),
                    pos_y = $drag.offset().top + drg_h - e.pageY,
                    pos_x = $drag.offset().left + drg_w - e.pageX;
                $drag.css('z-index', 1000).parents().on("mousemove", function (e) {
                    $('.draggable').offset({
                        top: e.pageY + pos_y - drg_h,
                        left: e.pageX + pos_x - drg_w
                    }).on("mouseup", function () {
                        $(this).removeClass('draggable').css('z-index', z_idx);
                    });
                });
                e.preventDefault(); // disable selection
            }).on("mouseup", function () {
                if (opt.handle === "") {
                    $(this).removeClass('draggable');
                } else {
                    $(this).removeClass('active-handle').parent().removeClass('draggable');
                }
            });
    
        }
    })(jQuery);
    
    $(document).ready(function () {
      $('#modal').on('shown.bs.modal', function () {
                    $(this).find('.card-header').drags();
                });

                $('#modal').modal({ show: true, backdrop: 'static', keyboard: false });
    });
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/js/bootstrap.bundle.min.js"></script>
<div id="modal" class="modal fade">
        <div class="modal-dialog modal-dialog-centered modal-lg">
            <div class="modal-content  animated bounceInRight">
                <div class="modal-body">
                    <div class="card">
                        <div class="card-header border-bottom-0">My super title</div>
                        <div class="card-body">
                            <form></form>
                        </div>
                    </div>
                </div>
                <div class="modal-footer">
                    <button type="submit" class="btn btn-success" id="btnAlmacenar"><i class="fa fa-save"></i> Almacenar</button>
                    <button type="button" class="btn btn-danger" data-dismiss="modal"><i class="fa fa-close"></i> Cancelar</button>
                </div>
            </div>
        </div>
    </div>

Related