14

I have this html:

<table>
    <tr>
        <td>
            Set right order
        </td>
        <td>
            <span style = "display: block;">asd | <a href = '#' onclick = "moveChoiceTo(this, -1);">&uarr;</a><a href = '#' onclick = "moveChoiceTo(this, 1);">&darr;</a></span>
            <span style = "display: block;">dsa | <a href = '#' onclick = "moveChoiceTo(this, -1);">&uarr;</a><a href = '#' onclick = "moveChoiceTo(this, 1);">&darr;</a></span>
            <span style = "display: block;">qwe | <a href = '#' onclick = "moveChoiceTo(this, -1);">&uarr;</a><a href = '#' onclick = "moveChoiceTo(this, 1);">&darr;</a></span>
            <span style = "display: block;">ewq | <a href = '#' onclick = "moveChoiceTo(this, -1);">&uarr;</a><a href = '#' onclick = "moveChoiceTo(this, 1);">&darr;</a></span>
        </td>
    </tr>
</table>

And this JS:

function moveChoiceTo(elem_choice, direction)
{
    var curr_index = -1; //index of elem that we should move
    var td = elem_choice.parentElement.parentElement; //link to TD

    for (var i = 0; i < td.children.length; i++) //determine index of elem that called this function
        if (td.children[i].children[0] == elem_choice)
        {
            curr_index = i;
            break;
        }

    if (curr_index == -1)
        return;

    if (curr_index == 0 && direction < 0) //if nowhere to move
        return;

    if (curr_index == td.children.length - 1 && direction > 0) //if nowhere to move
        return;

    var curr_child = td.children[curr_index]; //save current elem into temp var
    td.children.splice(curr_index, 1); //here I getting exception that splice isn't supported by object, but arent this is array?
    td.children.splice(curr_index + direction, 0, curr_child); //attempt to insert it
}

I getting exception that splice isn't supported, but this supposed to be an array and support this method? What other ways I have to change children order?

3
  • I think it would be easier of you used jQuery to solve this. Commented Sep 15, 2014 at 14:34
  • “but this supposed to be an array” – no, it’s not – it’s an HTMLCollection Commented Sep 15, 2014 at 14:48
  • As CBroe said, and HTMLCollection has no method splice(), but you can use Array.splice on it: [].splice.call(td.children, curr_index, 1); Commented Sep 15, 2014 at 14:52

3 Answers 3

24

I will add the answer with simpler (and better) approach:

function moveChoiceTo(elem_choice, direction) {

    var span = elem_choice.parentNode,
        td = span.parentNode;

    if (direction === -1 && span.previousElementSibling) {
        td.insertBefore(span, span.previousElementSibling);
    } else if (direction === 1 && span.nextElementSibling) {
        td.insertBefore(span, span.nextElementSibling.nextElementSibling)
    }
}

The key idea is using insertBefore method properly. You also don't need to remove anything from DOM.

Demo: http://jsfiddle.net/dq8a0ttt/

Sign up to request clarification or add additional context in comments.

3 Comments

This is awesome, but I feel bad for removing accepted answer, since it also is valid. By the way, is this fine for IE6 - IE8?
No problem, you don't have to :) Just make sure you use DOM methods properly in future. splice for arrays, not NodeList's.
Meh, I can't sleep well while this one is not the best. It's ULTIMATE best answer. Easy, small and elegant.
5

Splice is not supproted in HTMLCollection, you need to use .removeChild and .insertBefore something like this:

var before = td.children[curr_index + direction];
var child = td.children[curr_index];

td.removeChild(child);
td.insertBefore(child, before); //attempt to insert it      

2 Comments

even through your code is no correct handling for down arrow presses (because it will insert exactly in same place), it still gives the basic idea.
td.removeChild(child); is not needed, since insertBefore will move element if it's already in DOM.
0

Same as dfsq's answer but with some modifications.

var selected_element;


function moveElementTo(selected_element, direction) {

    var element_to_move = selected_element,
        td = element_to_move.parentNode;

    if (direction === -1 && element_to_move.previousElementSibling) {
        td.insertBefore(element_to_move, element_to_move.previousElementSibling);
    } else if (direction === 1 && element_to_move.nextElementSibling) {
        td.insertBefore(element_to_move, element_to_move.nextElementSibling.nextElementSibling)
    }
}



function move(dir){
    if (selected_element != undefined){
        moveElementTo(selected_element,dir);
    }else{
        console.error("No element Selected to move!");
    }

}
<div >

    <div onclick='selected_element = this;'><button onclick='selected_element = this.parentNode;'> Select element </button>Element One <button onclick='move(-1);'>Move_up</button></div>
    <div onclick='selected_element = this;'><button onclick='selected_element = this.parentNode;'> Select element </button>Element Two <button onclick='move(-1);'>Move_up</button></div>
    <div onclick='selected_element = this;'><button onclick='selected_element = this.parentNode;'> Select element </button>Element Three <button onclick='move(-1);'>Move_up</button></div>


</div>

My scenario for this was An element needs to be selected first, because I use it for a popup dialogue for which the operations show up upon long click, the Select Element button is just for demo.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.