2

I have a load of divs that area ll floated left so they sit next to eachother in rows that fill a page. I want to change the order they are in programmatically and still have them floated.

I have a piece of JS that I wrote which grabs the offset of each box, gives them a fixed position (using the offset so they stay in place), and then animates them to one of the other offsets. My problem is that I now need to convert them back from absolute positioning back to floated positioning. Doing this obviously reverts them back to how they were originally.

What I need to know is whether it is possible to set the index of each div - so I could associate an offset with an index and update each divs offset and index so that when they're floated they stay in place. Is there a way to set DOM elements' index using jQuery?

ollie
  • 799
  • 2
  • 10
  • 24

3 Answers3

5

You don't want to set their index, per se; you want to literally change their order in their container.

This is easy (with the DOM or with jQuery): If you want to move an element in front of its previous sibling, use insertBfore prev:

var elm = $("selector_for_the_element");
elm.insertBefore(elm.prev());

...or after its next sibling, use insertAfter next:

var elm = $("selector_for_the_element");
elm.insertAfter(elm.next());

Presumably you'd do this when done animating, reverting the divs back to being floated rather than absolutely-positioned.

Live example | source

HTML:

<div id="container"></div>

CSS:

#container div {
  float: left;
  width: 4em;
  border: 1px solid black;
  margin: 2px;
  padding: 2px;
}
.left, .right {
  cursor: pointer;
  font-weight: bold;
  font-size: 14pt;
  background-color: #eee;
  border: 1px solid #aaa;
}

JavaScript:

jQuery(function($) {

  var container = $("#container");
  var index;

  for (index = 0; index < 10; ++index) {
    $("<div>d" + index +" <span class='left'>&lt;</span> <span class='right'>&gt;</span></div>")
      .appendTo(container)
      .attr("id", "d" + index);
  }

  container.delegate(".left", "click", function() {
    var div = $(this).closest("div"),
        prev = div.prev();
    if (prev[0]) {
      div.insertBefore(prev);
    }
  });
  container.delegate(".right", "click", function() {
    var div = $(this).closest("div"),
        next = div.next();
    if (next[0]) {
      div.insertAfter(next);
    }
  });

});
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • @T.JCrowder wouldn't he need to toggle their positioning from absolute back to static? – Kevin Bowersox Jul 04 '12 at 09:31
  • @kmb385: Of course, I took that as read. I've made it explicit now. – T.J. Crowder Jul 04 '12 at 09:38
  • That looks perfect; thanks. Only question is something I forgot to mention - the divs are going to be animated to random (albeit preset) positions so I'm not sure how to achieve that with only insertBefore and insertAfter – ollie Jul 04 '12 at 09:57
  • 1
    @ollie: You can use [`offset`](http://api.jquery.com/offset/) and `width` to figure out which of the element's siblings it overlaps, which tells you where to move it. For instance, if the `left` of your animated element is 250, find the sibling that has `left <= 250` and `(left + width) > 250`. Then use `insertBefore` to snap the animated element into place before that sibling. – T.J. Crowder Jul 04 '12 at 10:03
  • Sorry, I marked this question as unanswered as this solution didn't work for me as I have thousands of elements and it's making the browser time out – ollie Jul 09 '12 at 15:20
0

Before you begin your animation that rearranges the divs, could you store their original positions and ids in an array of objects? Then have a function that iterates through the objects in that array calling an animation with their original positions as the coordinates?

Working Example: http://jsfiddle.net/JpVS4/3/

Html:

<div class="moving">Item 1</div>
<div class="moving">Item 2</div>
<div class="moving">Item 3</div>
<div id="move-back">Click to Move To Orignal Pos</div>

CSS:

.moving{
    width: 100px;
    float:left;
}


#move-back{
    position: absolute;
    top: 200px;
    border: 1px solid lightgray;
}

Javascript:

var originalPos =[];

//Store Original

    $(".moving").each(function(){
        originalPos.push({"left":$(this).position().left,"top":$(this).position().top});
    });

    //rearrange
    $(".moving").each(function(i,e){
        $(this).css("position", "absolute");
        $(this).css("left",100 * ((3-i)-1));                
    });


    //move back to original - if needed you could also set top
    $("#move-back").click(function(){
        $(".moving").each(function(i,e){
            var position = originalPos[i];
            $(this).css("left",originalPos[i].left);                
        });
    });
Kevin Bowersox
  • 93,289
  • 19
  • 159
  • 189
0

In the end I modified the solution to this question to meet my needs and worked really well:

Randomize a sequence of div elements with jQuery

Thanks a lot to the help from T.J. Crowder

Community
  • 1
  • 1
ollie
  • 799
  • 2
  • 10
  • 24