Search code examples
javascriptjqueryjquery-uicontainment

JQuery-UI containment: 'parent' does not work


As you see here, div with the class .foo is draggable and has containment: 'parent' option, so it must stay in the bounds of its parent div, which is mainDiv, but it does not. Why is that?

$(document).ready(function () {
    $('#deviceName li').draggable({
        helper: 'clone',
        revert: 'invalid'
    });
    $('#interface li').draggable({
        helper: 'clone',
        revert: 'invalid'
    });
    $('#display li').draggable({
        helper: 'clone',
        revert: 'invalid'
    });
    $('#output li').draggable({
        helper: 'clone',
        revert: 'invalid'
    });
    $('.foo').each(function(){
        $(this).draggable({
            containment: $(this).parent()
        });
    });
    $('#mainDiv').droppable({
        drop: function (event, ui) {
            if(ui.draggable.hasClass('foo')){
                
            }
            else {
                var title = ui.draggable.text().trim();
                var item = $('<div class="foo">').append('<table class="elementTable"><tr><th class="thClass">' + title + '</th></tr></table>');
                item.draggable();
                $(this).append(item);
            }
        }
    });
});
html{
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
    background: #2c2c2c;
    background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzJjMmMyYyIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjM3JSIgc3RvcC1jb2xvcj0iIzNkM2QzZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjY2JSIgc3RvcC1jb2xvcj0iIzM1MzUzNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjY2JSIgc3RvcC1jb2xvcj0iIzM1MzUzNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMxMzEzMTMiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
    background: -moz-linear-gradient(left, #2c2c2c 0%, #3d3d3d 37%, #353535 66%, #353535 66%, #131313 100%);
    background: -webkit-gradient(linear, left top, right top, color-stop(0%,#2c2c2c), color-stop(37%,#3d3d3d), color-stop(66%,#353535), color-stop(66%,#353535), color-stop(100%,#131313));
    background: -webkit-linear-gradient(left, #2c2c2c 0%,#3d3d3d 37%,#353535 66%,#353535 66%,#131313 100%);
    background: -o-linear-gradient(left, #2c2c2c 0%,#3d3d3d 37%,#353535 66%,#353535 66%,#131313 100%);
    background: -ms-linear-gradient(left, #2c2c2c 0%,#3d3d3d 37%,#353535 66%,#353535 66%,#131313 100%);
    background: linear-gradient(to right, #2c2c2c 0%,#3d3d3d 37%,#353535 66%,#353535 66%,#131313 100%);
    filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2c2c2c', endColorstr='#131313',GradientType=1 );
}
body{
    margin: 0;
    padding: 0;
    width: 100%;
    height: 100%;
}
#leftDiv{
    display: inline-block;
    width: 16%;
    min-height: 100%;
    border-right: 3px solid white;
    box-sizing: border-box;
    float: left;
    margin: 0;
    padding: 5px;
}
#mainDiv{
    display: inline-block;
    width: 64%;
    min-height: 100%;
    border-right: 3px solid white;
    box-sizing: border-box;
    float: left;
    margin: 0;
    padding: 5px;
}
#rightDiv{
    display: inline-block;
    width: 20%;
    box-sizing: border-box;
    min-height: 100%;
    float: left;
    margin: 0;
    padding: 5px;
}
.foo{
    max-width: 250px;
    text-align: center;
    min-height: 50px;
    border: 1px solid white;
    border-radius: 10px;
}
.foo table{
    width: 100%;
}
.thClass{
    border-radius: 10px;
    border-bottom: 1px solid white;
    margin: 0;
    padding: 0;
    width: 100%;
    text-align: center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>Test</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/overcast/jquery-ui.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
</head>
<body style="font-family: Arial; color: white;">
    <div id="leftDiv">
        <ul id="menu">
            <li>Device Name
                <ul id="deviceName">
                    <li>
                      item 1
                    </li>
                </ul>
            </li>
            <li>Interface
                <ul id="interface">
                    <li>
                      item 2
                    </li>
                </ul>
            </li>
            <li>Display
                <ul id="display">
                    <li>
                      item 3
                    </li>
                </ul>
            </li>
            <li>Output
                <ul id="output">
                    <li>
                      item 4
                    </li>
                </ul>
            </li>
        </ul>
    </div>
    <div id="mainDiv">
    
    </div>
    <div id="rightDiv">
    
    </div>
</body>
</html>

As you see here, div with the class .foo is draggable and has containment: 'parent' option, so it must stay in the bounds of its parent div, which is mainDiv, but it does not. Why is that?


Solution

  • Try with the following:

    $('.foo').each(function(){
        $(this).draggable({
            containment: $(this).parent()
        });
    });
    

    Reason is that the containment option can also be a jquery selector or an actual element.

    You can try it in this demo

    $('.foo').each(function() {
      $(this).draggable({
        containment: $(this).parent()
      });
    });
    

    The above code is called before the elements was created. So wrap them in a function can call it when a new object is created.

    function foo(){
      $('.foo').each(function() {
        $(this).draggable({
          containment: $(this).parent()
        });
      });
    }
    

    Working snippet

    $(document).ready(function() {
      $('#deviceName li').draggable({
        helper: 'clone',
        revert: 'invalid'
      });
      $('#interface li').draggable({
        helper: 'clone',
        revert: 'invalid'
      });
      $('#display li').draggable({
        helper: 'clone',
        revert: 'invalid'
      });
      $('#output li').draggable({
        helper: 'clone',
        revert: 'invalid'
      });
    function foo(){
      $('.foo').each(function() {
        $(this).draggable({
          containment: $(this).parent()
        });
      });
    }
      $('#mainDiv').droppable({
        drop: function(event, ui) {
          if (ui.draggable.hasClass('foo')) {
    
          } else {
            var title = ui.draggable.text().trim();
            var item = $('<div class="foo">').append('<table class="elementTable"><tr><th class="thClass">' + title + '</th></tr></table>');
            item.draggable();
            $(this).append(item);
            foo()
          }
        }
      });
    });
    html {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
      background: #2c2c2c;
      background: url(data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiA/Pgo8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgd2lkdGg9IjEwMCUiIGhlaWdodD0iMTAwJSIgdmlld0JveD0iMCAwIDEgMSIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+CiAgPGxpbmVhckdyYWRpZW50IGlkPSJncmFkLXVjZ2ctZ2VuZXJhdGVkIiBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMCUiPgogICAgPHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzJjMmMyYyIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjM3JSIgc3RvcC1jb2xvcj0iIzNkM2QzZCIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjY2JSIgc3RvcC1jb2xvcj0iIzM1MzUzNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjY2JSIgc3RvcC1jb2xvcj0iIzM1MzUzNSIgc3RvcC1vcGFjaXR5PSIxIi8+CiAgICA8c3RvcCBvZmZzZXQ9IjEwMCUiIHN0b3AtY29sb3I9IiMxMzEzMTMiIHN0b3Atb3BhY2l0eT0iMSIvPgogIDwvbGluZWFyR3JhZGllbnQ+CiAgPHJlY3QgeD0iMCIgeT0iMCIgd2lkdGg9IjEiIGhlaWdodD0iMSIgZmlsbD0idXJsKCNncmFkLXVjZ2ctZ2VuZXJhdGVkKSIgLz4KPC9zdmc+);
      background: -moz-linear-gradient(left, #2c2c2c 0%, #3d3d3d 37%, #353535 66%, #353535 66%, #131313 100%);
      background: -webkit-gradient(linear, left top, right top, color-stop(0%, #2c2c2c), color-stop(37%, #3d3d3d), color-stop(66%, #353535), color-stop(66%, #353535), color-stop(100%, #131313));
      background: -webkit-linear-gradient(left, #2c2c2c 0%, #3d3d3d 37%, #353535 66%, #353535 66%, #131313 100%);
      background: -o-linear-gradient(left, #2c2c2c 0%, #3d3d3d 37%, #353535 66%, #353535 66%, #131313 100%);
      background: -ms-linear-gradient(left, #2c2c2c 0%, #3d3d3d 37%, #353535 66%, #353535 66%, #131313 100%);
      background: linear-gradient(to right, #2c2c2c 0%, #3d3d3d 37%, #353535 66%, #353535 66%, #131313 100%);
      filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#2c2c2c', endColorstr='#131313', GradientType=1);
    }
    
    body {
      margin: 0;
      padding: 0;
      width: 100%;
      height: 100%;
    }
    
    #leftDiv {
      display: inline-block;
      width: 16%;
      min-height: 100%;
      border-right: 3px solid white;
      box-sizing: border-box;
      float: left;
      margin: 0;
      padding: 5px;
    }
    
    #mainDiv {
      display: inline-block;
      width: 64%;
      min-height: 100%;
      border-right: 3px solid white;
      box-sizing: border-box;
      float: left;
      margin: 0;
      padding: 5px;
    }
    
    #rightDiv {
      display: inline-block;
      width: 20%;
      box-sizing: border-box;
      min-height: 100%;
      float: left;
      margin: 0;
      padding: 5px;
    }
    
    .foo {
      max-width: 250px;
      text-align: center;
      min-height: 50px;
      border: 1px solid white;
      border-radius: 10px;
    }
    
    .foo table {
      width: 100%;
    }
    
    .thClass {
      border-radius: 10px;
      border-bottom: 1px solid white;
      margin: 0;
      padding: 0;
      width: 100%;
      text-align: center;
    }
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    
    <head runat="server">
      <title>Test</title>
      <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
      <link href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.18/themes/overcast/jquery-ui.css" rel="stylesheet" />
      <script src="https://ajax.googleapis.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
    </head>
    
    <body style="font-family: Arial; color: white;">
      <div id="leftDiv">
        <ul id="menu">
          <li>Device Name
            <ul id="deviceName">
              <li>
                item 1
              </li>
            </ul>
          </li>
          <li>Interface
            <ul id="interface">
              <li>
                item 2
              </li>
            </ul>
          </li>
          <li>Display
            <ul id="display">
              <li>
                item 3
              </li>
            </ul>
          </li>
          <li>Output
            <ul id="output">
              <li>
                item 4
              </li>
            </ul>
          </li>
        </ul>
      </div>
      <div id="mainDiv">
    
      </div>
      <div id="rightDiv">
    
      </div>
    </body>
    
    </html>