5
votes

I am trying to create this behavior and not sure whether Gridstack supports it or not. I have 3 Gridstack grids: Grid1, Grid2, and Grid3. Grid1 is a standalone grid and Grid3 is nested inside Grid2. I need to be able to drag widgets from Grid1 both into Grid2 (outer grid) and into Grid3 (nested grid). Following samples I was able to drag widgets between 2 top level grids and create a nested grid, but not combining these 2 together. If this is supported - any pointers are appreciated.

NB: Expand the snippet to full screen

$(document).ready(function() {
  $('.grid-stack').gridstack();
});
.grid-stack {
  background: lightgoldenrodyellow;
}

.grid-stack-item-content {
  color: #2c3e50;
  text-align: center;
  background-color: #18bc9c;
}

.grid-stack .grid-stack {
  /*margin: 0 -10px;*/
  background: rgba(255, 255, 255, 0.3);
}

.grid-stack .grid-stack .grid-stack-item-content {
  background: lightpink;
}
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.min.css" />


<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.0/jquery-ui.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>
<script type="text/javascript" src='//cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.min.js'></script>
<script type="text/javascript" src='//cdnjs.cloudflare.com/ajax/libs/gridstack.js/0.4.0/gridstack.jQueryUI.min.js'></script>


<div class="container-fluid">
  <h1> Multilevel Nested grids demo</h1>
  <div class="grid-stack" id="container-stack">
    <div class="grid-stack-item" data-gs-x="0" data-gs-y="0" data-gs-width="4" data-gs-height="4">
      <div class="grid-stack-item-content">
        <span>Grid One</span>
        <div class="grid-stack" id="grid-one">
          <div class="grid-stack-item widget" data-gs-x="0" data-gs-y="0" data-gs-width="3" data-gs-height="1">
            <div class="grid-stack-item-content">1</div>
          </div>
          <div class="grid-stack-item widget" data-gs-x="3" data-gs-y="0" data-gs-width="3" data-gs-height="1">
            <div class="grid-stack-item-content">2</div>
          </div>
        </div>
      </div>
    </div>
    <div class="grid-stack-item" data-gs-x="4" data-gs-y="0" data-gs-width="8" data-gs-height="4">
      <div class="grid-stack-item-content">
        <span>Grid Two</span>
        <div class="grid-stack" id="grid-two">
          <div class="grid-stack-item widget" data-gs-x="0" data-gs-y="0" data-gs-width="3" data-gs-height="1">
            <div class="grid-stack-item-content">3</div>
          </div>
          <div class="grid-stack-item widget" data-gs-x="3" data-gs-y="0" data-gs-width="3" data-gs-height="1">
            <div class="grid-stack-item-content">4</div>
          </div>
          <div class="grid-stack-item" data-gs-x="6" data-gs-y="0" data-gs-width="6" data-gs-height="3">
            <div class="grid-stack-item-content">
              <span>Grid Three</span>
              <div class="grid-stack" id="grid-three">
                <div class="grid-stack-item widget" data-gs-x="0" data-gs-y="0" data-gs-width="6" data-gs-height="1">
                  <div class="grid-stack-item-content">5</div>
                </div>
                <div class="grid-stack-item widget" data-gs-x="6" data-gs-y="0" data-gs-width="6" data-gs-height="1">
                  <div class="grid-stack-item-content">6</div>
                </div>
              </div>
            </div>
          </div>

        </div>

      </div>
    </div>
  </div>
</div>
2
could you add some sample code of what you have tried? - Rachel Gallen
@RachelGallen I pretty much downloaded and played around with these 2 examples: 1 - dragging widget from grid to grid: gridstackjs.com/demo/two.html and 2 - nested grid: gridstackjs.com/demo/nested.html. But I couldn't make these 2 pieces work together. - Yuriy Galanter
From what I could see from the demo, the library only seems to support rearranging of tiles, but you can't drop one inside another or anything (like a small inside a large) , they're not allboth draggable and droppable areas. I didn't look at the nested example, I didn't see it. You could probably adjust the grid stack J's to make them both drag and drop if that's what you wanted. I saw where it was set in the js last night. - Rachel Gallen
Thanks, I will see if I can put on fiddle snippets I've been experimenting with. And thanks for the suggestions. You're right I might have to go outside of gridstack API to something more generic. - Yuriy Galanter
@Towkir still tweaking around with various approaches, but the more I look into this the more it seems it will be a hack if I want to at least emulate the behavior. E.g. for the duration of the drop take inner grid out of the widget (DOM-wise) and attach it to the body of the document (while keeping its location in the same place). - Yuriy Galanter

2 Answers

4
votes

Following samples I was able to drag widgets between 2 top level grids and create a nested grid, but not combining these 2 together. If this is supported

Sad but true, that's not possible. At least, not with gridstack.

The key behind this dragging mechanism is accomplished by the acceptWidgets option. But this can't handle multilevel .grid-stack element. Hence, error appears.

You can try to modify the script added in the snippet to something like this:

$("#container-stack").gridstack({
   acceptWidgets: '.grid-stack-item'
})

But sadly, this will cause error once you start dragging any widget. But it works with single level nesting, which is not definitely what you are looking for.

The documentation also does not indicate anything at all regarding the nested level dragging.

But the reason I am assuming this isn't possible is this issue, also this one.

I guess this is (almost) exactly what you wanted. but there is no response from any officials. Also, it's three years old. Another flaw that indicates this project is dying is when you try to access some of their files such as the script, you get a security warning, which prevented me to add this snippet for a while.


Therefore, if I were you I would go for jqueryUI and custom code this.


Update

Here is a snippet of something similar to what you expected I guess, let me know if this is right, then I will improve this once again, like adding resizing, snap to sibling widgets and a few more things:

Once again, check the snippet in fullscreen mode.

$("#gridThree").draggable({
  snap: '#gridTwo',
  snapMode: 'inner',
  zIndex: 5,
  containment: 'parent'
});

$(".widgetInOne, .widgetInTwo, .widgetInThree").draggable({
  snap: '#gridOne, #gridTwo, #gridThree',
  snapMode: 'inner',
  zIndex: false,
  stack: 'div',
  cursor: 'grab',
  // grid: [ 100, 100 ]
});

$("#gridOne, #gridTwo, #gridThree").droppable({
  accept: '.widgetInOne, .widgetInTwo, .widgetInThree',
  drop: function(event, ui) {
    if ($(event.target).find($(event.toElement)).length == 0) {
      $(event.toElement).css({
        'left': '',
        top: ''
      });
      $(event.target).append($(event.toElement));
    }
  }
});
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

#gridOne {
  background: #cecece;
  width: 40%;
  height: 400px;
  display: inline-block;
  margin-right: 4%;
  vertical-align: top;
}

.widgetInOne,
.widgetInTwo,
.widgetInThree {
  width: 100px;
  height: 100px;
  padding: 0.5em;
}

#gridTwo {
  background: #bfe9f3;
  width: 50%;
  height: 400px;
  display: inline-block;
  margin-left: 4%;
  vertical-align: top;
  position: relative;
}

#gridThree {
  background: #ffdda9;
  width: 300px;
  height: 300px;
  display: inline-block;
  vertical-align: top;
  position: absolute;
  right: 100px;
  top: 0;
}
<link rel="stylesheet" href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css">
<link rel="stylesheet" href="https://jqueryui.com/resources/demos/style.css">
<script src="https://code.jquery.com/jquery-1.12.4.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>



<div id="gridOne">
  <div class="ui-widget-content widgetInOne">
    <p>One</p>
  </div>
</div>


<div id="gridTwo">
  <div class="ui-widget-content widgetInTwo">
    <p>Two</p>
  </div>
  <div id="gridThree">
    <div class="ui-widget-content widgetInThree">
      <p>Three</p>
    </div>
  </div>
</div>

A Few Notable things here:

  • When you drag a widget into a grid, the widget element actually moves in that grid (in the DOM structure), so any parent dependent css selector might not work here. only apply css with the widget class.
  • For now the widgets only snaps to the grid inner edges (not to the outer side of other widgets), to find more check: here I couldn't find any other option but to use // grid: [ 100, 100 ] for this one.

  • Resizable option is not added here yet, hope you can tweak it as you need

3
votes

This is code from an old drag/drop fiddle I composed (an age ago!), with areas that are both draggable and droppable. The items that can be pulled across to either of the droppable areas can be dragged again from one area to another and dragged up and down. While the items are not sized the same as are in your example, it goes to show that the same user experience can be achieved by using simply jquery/jquery-ui without sticking to gridstack. You may save yourself some laborious hours by working outside the grid! ;)

Hope this helps

fiddle

$("#launchPad").height($(window).height() - 20);
var dropSpace = $(window).width() - $("#launchPad").width();
$("#dropZone").width(dropSpace - 70);
$("#dropZone").height($("#launchPad").height());

$(".card").draggable({
  appendTo: "#launchPad",
  cursor: "move",
  helper: 'clone',
  revert: "invalid",

});

$("#launchPad").droppable({
  tolerance: "intersect",
  accept: ".card",
  activeClass: "ui-state-default",
  hoverClass: "ui-state-hover",
  drop: function(event, ui) {
    $("#launchPad").append($(ui.draggable));
  }
});

$(".stackDrop1").droppable({
  tolerance: "intersect",
  accept: ".card",
  activeClass: "ui-state-default",
  hoverClass: "ui-state-hover",
  drop: function(event, ui) {
    $(this).append($(ui.draggable));
  }
});

$(".stackDrop2").droppable({
  tolerance: "intersect",
  accept: ".card",
  activeClass: "ui-state-default",
  hoverClass: "ui-state-hover",
  drop: function(event, ui) {
    $(this).append($(ui.draggable));
  }
});
body {
  margin: 0;
}

#launchPad {
  width: 200px;
  float: left;
  border: 1px solid #eaeaea;
  background-color: #f5f5f5;
}

#dropZone {
  float: right;
  border: 1px solid #eaeaea;
  background-color: #ffffcc;
}

.card {
  width: 150px;
  padding: 5px 10px;
  margin: 5px;
  border: 1px solid #ccc;
  background-color: #eaeaea;
}

.stack {
  width: 180px;
  border: 1px solid #ccc;
  background-color: #f5f5f5;
  margin: 20px;
}

.stackHdr {
  background-color: #eaeaea;
  border: 1px solid #fff;
  padding: 5px
}

.stackDrop1,
.stackDrop2 {
  min-height: 100px;
  padding: 15px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.js"></script>




<body>
  <div id="launchPad">
    <div class="card draggable">
      apple
    </div>
    <div class="card draggable">
      orange
    </div>
    <div class="card draggable">
      banana
    </div>
    <div class="card draggable">
      car
    </div>
    <div class="card draggable">
      bus
    </div>
  </div>

  <div id="dropZone">
    <div class="stack">
      <div class="stackHdr">
        Drop here
      </div>
      <div class="stackDrop1 droppable">

      </div>
    </div>

    <div class="stack">
      <div class="stackHdr">
        Or here
      </div>
      <div class="stackDrop2 droppable">

      </div>
    </div>
  </div>