user1
user1

Reputation: 1065

Rearrange Html elements

I have four div elements

    <div id="one" class="present" style="display: none;">1</div>
    <div id="two" class="present" style="display: none;">2</div>
    <div id="three" class="present" style="display: none;">3</div>
    <div id="four" class="present" style="display: none;">4</div>

At some point if it becomes

    <div id="one" class="present" style="display: none;">1</div>
    <div id="two" class="present" style="display: none;"></div>//this value gets deleted
    <div id="three" class="present" style="display: none;">3</div>
    <div id="four" class="present" style="display: none;">4</div>

I want it to get rearrange as

    <div id="one" class="present" style="display: none;">1</div>
    <div id="two" class="present" style="display: none;">3</div>//this moves up
    <div id="three" class="present" style="display: none;">4</div>//this moves up
    <div id="four" class="present" style="display: none;"></div>

Only these four elements have class "present" so I would think I could do something by iterating through it, but not sure how to get the result i am looking for

I tried:

    $(".present").each(function(){

    if ($(this).is(":empty"))
    {
        var target =  $(this);
        $(".present").each(function(){
             $(this).not(":empty");
             target.html($(this).html());
        });
    }
});

but this seem to put last div's html on the blank space, which is not what i want. I want them to push up.

ps: its not just one value that might get deleted. Any value in middle can get deleted. Even multiple values can get deleted, meaning, I could only have value in the last div, which i would ideally want to move to first div

Upvotes: 0

Views: 1585

Answers (5)

Givi
Givi

Reputation: 1734

Simple solution... (or maybe alternative)
Live Demo

function check(id) {
    var ele = document.getElementById(id),
        parent = ele.parentNode,
        len = parent.children.length,
        child = null;

    for (var i = 0; i < len; i++) {
        child = parent.children[i];
        if (child.nodeType === 1 && child.innerHTML.length === 0) {
            parent.appendChild(child);
        }
    }
}

Upvotes: 0

wirey00
wirey00

Reputation: 33661

Just insert all empty ones after the last non empty one

$('.present:empty').insertAfter('.present:not(:empty):last');

http://jsfiddle.net/4QYjW/

EDIT:

I didn't notice that you are only moving the text - You can do it like this

var withText = $('.present:not(:empty)').clone();// get all with text
$('.present').text(''); // clear all the text
// loop through and add the number text
$.each(withText, function(i,v){
    $('.present').eq(i).text($(v).text()); 
});

http://jsfiddle.net/k42Ny/

Upvotes: 0

Nope
Nope

Reputation: 22339

I found a few issues in my last code.

I'm assuming from your original question that you don't want your div elements to be re-arranged but only your html content of each div.

Assuming you have this:

<div id="one" class="present">1</div>
<div id="two" class="present"></div>
<div id="three" class="present">3</div>
<div id="four" class="present"></div>
<div id="five" class="present">5</div>
<div id="six" class="present"></div>
<div id="seven" class="present"></div>
<div id="eight" class="present">8</div>
<div id="nine" class="present"></div>
<div id="ten" class="present"></div>

There probably is a shorter way but this seems to work.

$(".present").each(function () {
    var $this = $(this);

    if ($this.is(":empty")) {
        var $nextItem = $this.nextAll().not(':empty').first();

        console.log($nextItem.html());

        if($nextItem.length){
            $this.html($nextItem.html());
            $nextItem.empty();
        }
    }
});

The resulting HTML is:

<div id="one" class="present">1</div>
<div id="two" class="present">3</div>
<div id="three" class="present">5</div>
<div id="four" class="present">8</div>
<div id="five" class="present"></div>
<div id="six" class="present"></div>
<div id="seven" class="present"></div>
<div id="eight" class="present"></div>
<div id="nine" class="present"></div>
<div id="ten" class="present"></div>

DEMO - Use next non-empty value


As you can see in the resulting HTML, the div elements have not been re-ordered, just the HTML content has been shifted up, filling the blanks, thus leaving the blanks at the bottom. It works with multiple empty values missing in-between and at the end as well.

Upvotes: 3

relic
relic

Reputation: 1704

Pretty sure this will do the trick:

$(".present").each(function(){
  if ($(this).is(":empty")){
    $(this).append($(this).parent());
  }
});

The append function removes the element and appends it to the target. By appending it to the container it's already in, it should be removed from the dom and reinserted at the end which should allow the lower objects to naturally move up.

If you wanted to animate the effect, you could clone the object rather than append, then target the first instance of it, animate the height value to 0 and then remove it.


So, in order to maintain the proper IDs on the containers, you could replace the markup of each with the markup of the next object, but there's quite a bit of content juggling involved there. I would suggest something like this instead (you would need to alter your id naming scheme slightly, to make it a little easier to set up. Not sure if that's an option for your situation.)

var myObjects = $(".present");
$(myObjects).each(function(){
  if ($(this).is(":empty")){
    $(this).append($(this).parent());
  }
}).each(function(){
  $(this).attr('id', 'a' + ($(this).index() + 1) )
});

So your ids would be a1, a2, a3, etc... the letter is because you cannot start an id or a class with a number, but could be replaced with something more descriptive if needed.

Depending on how you're using those IDs, you could possible just get rid of them altogether and check the index() of the object directly in whatever functions are making use of the IDs.

So if you're doing something like this:

$("#one").stuff();

.. you could instead use:

$(".present:eq(0)").stuff();

Of course that probably wouldn't work as well if you're referencing specific IDs in the css.

Upvotes: 2

Matt Burland
Matt Burland

Reputation: 45155

Can't you simply do this:

$(".present:empty").each(function(index,item) {
    $(this).remove();
    $("#parent").append(this);
});

Just pull them out and add them back at the end of the list.

Here's a fiddle to illustrate.

Upvotes: 1

Related Questions