7

I'm trying to use jQuery to move an element from one location to another in the DOM. There are elements identical to the originating container alongside it, so how do I store its exact previous location so it will return back to it? Here's an example...

<div class="container"></div>
<ul>
    <li></li>
    <li><div class="move">Content</div></li>
    <li></li>
    <li><div class="move">Content</div></li>
    <li></li>
</ul>

...the "move" divs are individually moving to the "container" div, then back to their previous location on an event via jQuery .appendTo(). How do I ensure each "move" div returns to its exact previous location by detecting where it was moved from (its exact location in the DOM relative to the document, or an otherwise specified parent container)?

EDIT: I have corrected the classes on the divs since the specific case I'm working with has the list items being exact duplicates of one another (structurally), with unique content within their respective elements. Also, the event to move a "move" div back to its original location is a button clicked within it. How does the moved element know where to move back to once moved (specifically, how does it know which list item within the list)?

Charles
  • 167
  • 1
  • 5
  • 15
  • if you want better answers than the ones you already have, you should update your HTML to represent what you're asking. First, if you have "elements identical to the originating container alongside it" you can show 2 containers then. If your document "has the list items being exact duplicates of one another" remove their unique classes. – Fabrício Matté May 15 '12 at 00:09
  • I'd put an answer for your question as well, but with this HTML it's hard to tell what you're expecting exactly. – Fabrício Matté May 15 '12 at 01:05

3 Answers3

4

you can clone them, append them , and finally hide the original div, and in return remove the cloned div and show the original.

Ram
  • 143,282
  • 16
  • 168
  • 197
  • Exactly the same answer as I was typing. Think this is the best method. – Anonymous May 14 '12 at 22:15
  • 1
    Looks good, however if OP ever has to iterate through all the elements e.g. to grab the data and send to another page, he'd have to add a check with `.is(':visible')` though. – Fabrício Matté May 14 '12 at 22:17
  • @Fabrício Matté i don't think the contents of a div is useful to be stored on db. – Ram May 14 '12 at 22:24
  • 1
    @Raminson if OP is trying to reproduce a [sortable](http://jqueryui.com/demos/sortable/) feature with his divs/list items or he'd like to use the sorted divs/items for whatever reason, I just made a note that there would be duplicate elements and require one extra check. – Fabrício Matté May 14 '12 at 22:29
  • Your answer works for the given question though, I'll +1 it as soon as I can (I'm out of votes until UTC resets in about 1h 30min :P). – Fabrício Matté May 14 '12 at 22:35
  • Per my edit to the OP, if what you suggest is done how will the event that removes the second instance know which original div to show? – Charles May 14 '12 at 23:39
  • This adds elements to the document, which *may* work but is somewhat of a hack IMO. – Madbreaks May 14 '12 at 23:54
  • @charles by using its class, you can add an extra class when you are hiding the elements, like `hidden`. and alternatively you can use `index` or `eq` methods. – Ram May 15 '12 at 01:46
2

Before moving the element, store its .parent() in a variable, then use .append() or .appendTo() to return it when ready.

Ashley Strout
  • 6,107
  • 5
  • 25
  • 45
  • Neat answer, I didn't know the `.parent()` would store the relative index of the nested element which you're calling it from. Really useful info, I'll +1 it soon as well. – Fabrício Matté May 14 '12 at 22:38
  • I made a [fiddle](http://jsfiddle.net/ult_combo/BTKex/) to check the functionality of your code, I'm sure your code will be useful in the future. – Fabrício Matté May 14 '12 at 22:53
  • This won't work since per the op's question, "There are elements identical to the originating container alongside it". Simply storing the parent won't retain the element's position *in* the parent. – Madbreaks May 14 '12 at 23:37
  • @Madbreaks Yes, that hits at the main issue. I wonder, is there a base function in jQuery, or a plugin, that returns the exact DOM position of an element relative to the document? Similar to the XPath, as in Firebug Here's the XPath to your comment... /html/body/div[4]/div[2]/div/div[2]/div[2]/div[4]/table/tbody/tr[2]/td[2]/div/table/tbody/tr[3]/td[2]/div/span – Charles May 14 '12 at 23:51
  • HTML *is* XML, why not use xpath? http://docs.jquery.com/DOM/Traversing/Selectors#XPath_Selectors – Madbreaks May 14 '12 at 23:53
  • Depending on your markup, you could store the `.next()` element instead, and then do a `.insertBefore()` when moving the element back again. – naton Nov 10 '15 at 21:36
2

Below is what I did. Your post leaves out some important details so I'll guess and hopefully they'll apply to your situation.

I'm going to guess you have a click handler on the div.move elements that moves them into the container div.

CSS:

.placeholder { display:none; }

JS:

var id,
    gid = 0;

$('.move').click(function(e){
    if(!$(this).parents('.container')){
        // Move to container
        id = 'placeholder-' + gid++;
        $(this)
            .before('<div class="placeholder ' + id + '"></div>')  // Save a DOM "bookmark"
            .appendTo('.container')                               // Move the element to container
            .data('placeholder', id);                              // Store it's placeholder's info
    }
    else{
        // Move back out of container
        $(this)
            .appendTo('.placeholder.' + $(this).data('placeholder'))  // Move it back to it's proper location
            .unwrap()                               // Remove the placeholder
            .data('placeholder', undefined);        // Unset placeholder data
     }
 });

Your HTML would look like this after clicking on the first div.move:

<div class="container">
    <div class="move>Content</div>
</div>
<ul>
    <li></li>
    <li><div class="placeholder placeholder-0"></div></li>
    <li></li>
    <li><div class="move">Content</div></li>
    <li></li>
</ul>

I have this working, though the above code is untested. Hopefully it conveys the idea. What I like about this approach:

  1. No duplication of elements (which may break unique ID requirements, for example)
  2. Minimal DOM impact
  3. Events and handlers on moved items remain intact but are not duplicated

Is it perfect? No. But it works nicely and is pretty clean. YMMV.

Cheers

Madbreaks
  • 19,094
  • 7
  • 58
  • 72